ボタンやカードに少し動きを足すだけで、サイトの印象は大きく変わります。一方で、アニメーションは書き方を間違えると重くなったり、うるさく見えたりしがちです。
この記事では、CSS を中心にしたリッチな演出5つを、記事内デモとコピペ用コードで紹介します。
この記事でわかること
transitionとanimationの使い分け- シマーボタン・光る枠線カード・流れる文字・無限スライド・ローディングの5サンプル
- 記事内で動くデモと、HTML + CSS のコピペ用コード
- 重く・うるさくならないための使い方の目安(チェックリスト)
- アクセシビリティ向けの
prefers-reduced-motionの書き方
こんなときに読むと役立ちます
- LP やカード UI に、さりげないリッチ感を足したい
- アニメーションのコードを拾ったが、何が効いているか分解できない
- JS なしで、ホバーや読み込み演出を試したい
- 「かっこいいけど重そう」な演出を、CSS だけで軽く作りたい
まず押さえる:transition と animation
| プロパティ | 向いている場面 | 例 |
|---|---|---|
transition |
A 状態 → B 状態へのなめらかな変化 | ホバーで色・影・位置が変わる |
animation + @keyframes |
繰り返し・自動再生の動き | シマー、回転、流れるグラデ |
ホバーで反応するなら
transition、ページ表示やループ演出ならanimation、と最初に分けると迷いにくいです。
重くなりやすいのは、常時ループの animation を増やしすぎたり、width や box-shadow を毎フレーム動かす書き方です。うるさく見えやすいのは、同じページにループ演出を何個も並べるときです。下のサンプルでは、ホバー時だけ動かす・ループは1か所に絞るなど、抑えた書き方にしています。
サンプル1:シマーするグラデボタン
ホバーしたときだけ、光が横切るボタンです。::after 疑似要素と @keyframes で作ります。
ホバーしてみてください
HTML
<button type="button" class="shimmer-btn">送信する</button>
CSS
.shimmer-btn {
position: relative;
overflow: hidden;
border: none;
border-radius: 999px;
padding: 0.75em 1.6em;
color: #fff;
font-weight: 700;
background: linear-gradient(135deg, #3b82f6, #6366f1);
cursor: pointer;
}
.shimmer-btn::after {
content: "";
position: absolute;
top: 0;
left: -120%;
width: 60%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.45),
transparent
);
transform: skewX(-18deg);
}
.shimmer-btn:hover::after {
animation: shimmer 0.9s ease;
}
@keyframes shimmer {
to { left: 140%; }
}
ポイントは、光の帯を ボタンの外側から通過させることです。overflow: hidden でボタン内に収めます。HTML は button にクラスを付けるだけでOKです。
サンプル2:光る枠線が回るカード
カードの外周に、グラデーションの枠線がくるくる回る演出です。::before で回転する背景を敷き、内側を白で覆って枠線だけが光って見えるようにします。
新着記事
HTML
<div class="border-glow-card">
<div class="border-glow-card__inner">
<p class="card-title">新着記事</p>
</div>
</div>
CSS
.border-glow-card {
position: relative;
padding: 2px;
border-radius: 16px;
overflow: hidden;
isolation: isolate;
}
.border-glow-card::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 220%;
aspect-ratio: 1;
transform: translate(-50%, -50%);
background: conic-gradient(
from 0deg,
#3b82f6,
#8b5cf6,
#ec4899,
#3b82f6
);
animation: border-rotate 3s linear infinite;
z-index: 0;
}
.border-glow-card__inner {
position: relative;
z-index: 1;
padding: 1.25rem 1rem;
border-radius: 14px;
background: #fff;
}
@keyframes border-rotate {
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}
ポイントは、外側を overflow: hidden にして回転するグラデの一部だけを枠線として見せることです。ホバー不要で動くので、一覧カードの目立たせにも使えます。
サンプル3:流れるグラデーション文字
見出しやキャッチコピー向けの、グラデが横に流れる文字演出です。background-clip: text で文字の形にグラデを切り抜きます。
HTML
<span class="flow-text">Rich Animation</span>
CSS
.flow-text {
display: inline-block;
font-weight: 800;
background: linear-gradient(
90deg,
#3b82f6 0%,
#8b5cf6 25%,
#ec4899 50%,
#8b5cf6 75%,
#3b82f6 100%
);
background-size: 200% 100%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
animation: flow 5s linear infinite;
}
@keyframes flow {
0% { background-position: 0% 50%; }
100% { background-position: 200% 50%; }
}
ループの切り目で色がぱっと飛ぶときは、グラデを左右対称にして始点・終点の色を揃えます。background-size: 200% に対して background-position も 0% → 200% と同じ幅で動かすと、途切れず流れ続けます。
本文全体には使わず、短い見出し・ラベル程度に留めると読みやすさを保てます。
サンプル4:回転するローディング
読み込み中のくるくる回る円は、border の一部だけ色を変えて rotate させる定番パターンです。
HTML
<div class="spinner"></div>
CSS
.spinner {
width: 44px;
height: 44px;
border: 4px solid #e2e8f0;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
サンプル5:テキストが無限スライドするループ
お知らせ帯のように、背景なしで文字だけが横に流れ続ける演出です。同じ文言を marquee__item で4つ並べ、CSS で左へ動かします。1つ分どれだけ流すかは、横幅を自動調整しています。
HTML
<div class="marquee">
<div class="marquee__track">
<span class="marquee__item">HTML & CSS · JavaScript · </span>
<span class="marquee__item">HTML & CSS · JavaScript · </span>
<span class="marquee__item">HTML & CSS · JavaScript · </span>
<span class="marquee__item">HTML & CSS · JavaScript · </span>
</div>
</div>
CSS
.marquee {
overflow: hidden;
width: 100%;
}
.marquee__track {
display: flex;
width: max-content;
font-size: 0;
animation: marquee 20s linear infinite;
}
.marquee__item {
flex: 0 0 auto;
box-sizing: border-box;
padding-right: 2.5rem;
display: inline-block;
white-space: nowrap;
font-size: 0.95rem;
}
@keyframes marquee {
0% { transform: translate3d(0, 0, 0); }
100% { transform: translate3d(calc(-1 * var(--marquee-shift, 0px)), 0, 0); }
}
JavaScript(横幅を測る)
function initMarquees() {
document.querySelectorAll('.marquee').forEach((marquee) => {
const track = marquee.querySelector('.marquee__track');
const item = marquee.querySelector('.marquee__item');
if (!track || !item) return;
const updateShift = () => {
const width = item.getBoundingClientRect().width;
track.style.setProperty('--marquee-shift', `${width}px`);
};
updateShift();
new ResizeObserver(updateShift).observe(item);
document.fonts?.ready.then(updateShift);
});
}
document.addEventListener('DOMContentLoaded', initMarquees);
流す距離は --marquee-shift に、1つ目の marquee__item の幅を入れます。同じ文言を4つ並べるのは、ループが戻るときも画面内の見た目がつながるようにするためです。
アクセシビリティのワンポイント:prefers-reduced-motion
めまいのしやすさなどの理由で、OS の「アニメーションを減らす」設定をオンにしているユーザーがいます。そういうユーザー向けに prefers-reduced-motion を使えば、その設定のときだけループ・自動再生を止めることができます。
prefers-reduced-motion とは
ユーザーが動きを減らしたい設定のときだけ、CSS のアニメーションをオフにするメディアクエリ
止める対象は、常時ループする animation が中心です。transition まで止めるサイトもありますが、多くはループの animation だけを止める傾向にあるようです。この記事の例も同様に、ループの animation だけを止める形にしています。
書き方の例
@media (prefers-reduced-motion: reduce) {
.shimmer-btn::after,
.border-glow-card::before,
.flow-text,
.spinner,
.marquee__track {
animation: none;
}
}
記事内デモにも同じ考え方を入れています。Windows なら「設定 → ユーザー補助 → 視覚効果 → アニメーション効果を表示する」をオフにすると、デモのループが止まるか確認できます。
使うときのチェックリスト
導入で触れた「重く・うるさく見える」を避けるため、本番投入前に次を確認します。
- 動かすのは 色・影・位置・透明度 など、軽いプロパティか
- ホバー演出は
:hoverだけに頼らず、通常時との差が小さすぎないか確認したか - ループアニメは 1ページに何個も並べていないか
- 装飾目的のアニメが、本文の読みやすさを邪魔していないか
- 上の
prefers-reduced-motionを入れ、動きを減らす設定のときに止まるか確認したか
まとめ
- ホバー反応は
transition、ループ演出はanimation - シマー・光る枠線カード・流れる文字・無限スライド・スピナーの5つで、リッチ感の土台が作れる
prefers-reduced-motionで、ループ・自動再生だけ止められる
よければ、気になるサンプルをボタンやカードにコピーして、色や秒数を調整しながら使ってみてください。

