🎯 やりたかったことは?
SVGを扱っていると、
「マウスを乗せたときに色を変えたい」
「線が描かれていくように見せたい」
「アイコンを回転させたい」
といった動きを付けたくなることがあります。
JavaScriptを使わなくても、単純なアニメーションであればCSSだけで実装できます。
ただ、transform-origin や stroke-dashoffset などは、久しぶりに使うと毎回少し迷います。
そこで、SVGでよく使うCSSアニメーションをチートシートとしてまとめておきます。
🚀 急いでいる人向け
| やりたいこと | 主に使うもの |
|---|---|
| 色を滑らかに変える |
transition / fill / stroke
|
| フェードイン・アウト | opacity |
| 点滅させる |
@keyframes / opacity
|
| 回転させる | transform: rotate() |
| 拡大・縮小する | transform: scale() |
| 線を描いているように見せる |
stroke-dasharray / stroke-dashoffset
|
| アニメーション後の状態を維持する | animation-fill-mode: forwards |
| 繰り返す | animation-iteration-count: infinite |
| 一時停止する | animation-play-state: paused |
線を描いているように見せる場合は、次の形を覚えておくと使いやすいです。
<path
class="draw-line"
pathLength="100"
d="M20 80 C80 10 140 150 220 50"
fill="none"
stroke="#333"
stroke-width="4" />
.draw-line {
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: draw 1.5s ease forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
💡 この記事で分かること
- SVGの色をCSSで滑らかに変える方法
- 点滅・フェード・回転・拡大縮小の実装方法
- 線を描いているように見せる方法
- SVGで
transform-originを指定するときの注意点 - クラスを切り替えてアニメーションを開始する方法
- 動きを減らしたいユーザーへの配慮
CSSでSVGの色を変える
まずは、マウスを乗せたときに色を変える例です。
<svg
width="160"
height="100"
viewBox="0 0 160 100"
xmlns="http://www.w3.org/2000/svg">
<rect
class="color-change"
x="20"
y="20"
width="120"
height="60"
rx="8" />
</svg>
.color-change {
fill: #e5e7eb;
stroke: #333;
stroke-width: 2;
transition:
fill 0.2s ease,
stroke 0.2s ease;
}
.color-change:hover {
fill: #4caf50;
stroke: #1b5e20;
}
transition を指定しておくと、色が一瞬で切り替わらず、滑らかに変化します。
opacity でフェードさせる
表示・非表示を滑らかに切り替える場合は、opacity が使いやすいです。
<circle
class="fade-circle"
cx="50"
cy="50"
r="35" />
.fade-circle {
fill: #2196f3;
opacity: 0.3;
transition: opacity 0.3s ease;
}
.fade-circle:hover {
opacity: 1;
}
opacity は要素全体に適用されます。
塗りだけを変えたい場合は fill-opacity、線だけなら stroke-opacity も使えます。
点滅させる
@keyframes を使うと、一定間隔で点滅させられます。
<circle
class="blink-circle"
cx="50"
cy="50"
r="30" />
.blink-circle {
fill: #f44336;
animation: blink 1s ease-in-out infinite;
}
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.2;
}
}
infinite を指定しているため、アニメーションは繰り返されます。
一度だけ実行したい場合は infinite を外します。
SVG要素を回転させる
SVG要素を回転させるときは、transform-origin だけでなく transform-box も指定しておくと扱いやすいです。
<rect
class="rotate-shape"
x="30"
y="30"
width="60"
height="60"
rx="8" />
.rotate-shape {
fill: #ff9800;
transform-box: fill-box;
transform-origin: center;
animation: rotate 1.5s linear infinite;
}
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
transform-box: fill-box;
transform-origin: center;
を指定することで、対象要素の中央を基準に回転させています。
これがないと、想定していない位置を中心に回転することがあります。
拡大・縮小する
回転と同じように、transform-box と transform-origin を指定します。
<circle
class="pulse-circle"
cx="50"
cy="50"
r="25" />
.pulse-circle {
fill: #9c27b0;
transform-box: fill-box;
transform-origin: center;
animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.25);
}
}
このような拡大・縮小は、選択中の要素や通知アイコンを目立たせたい場合に使えます。
線を描いているように見せる
SVGでよく使われるのが、stroke-dasharray と stroke-dashoffset を使ったアニメーションです。
<svg
width="260"
height="160"
viewBox="0 0 260 160"
xmlns="http://www.w3.org/2000/svg">
<path
class="draw-line"
pathLength="100"
d="M20 80 C80 10 140 150 220 50"
fill="none"
stroke="#333"
stroke-width="4"
stroke-linecap="round" />
</svg>
.draw-line {
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: draw 1.5s ease forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
最初は線全体をずらして見えない状態にしておき、stroke-dashoffset を 0 に戻しています。
stroke-dashoffset: 100
→ 線が見えない
stroke-dashoffset: 0
→ 線全体が見える
pathLength="100" を付ける理由
実際のpathの長さは、図形によって異なります。
pathLength="100"
を付けると、この記事の例では長さを 100 として扱えるため、CSS側の値を揃えやすくなります。
pathLength を付けない場合は、pathの長さに合わせて stroke-dasharray と stroke-dashoffset を調整します。
塗りつぶしを後から表示する
線を描いたあとに塗りつぶしを表示することもできます。
<path
class="draw-and-fill"
pathLength="100"
d="M100 20 L180 140 L20 140 Z"
stroke="#333"
stroke-width="4" />
.draw-and-fill {
fill: transparent;
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation:
draw 1.5s ease forwards,
fill-shape 0.5s ease 1.5s forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
@keyframes fill-shape {
to {
fill: #4caf50;
}
}
2つ目のアニメーションに、
1.5s
の遅延を付けて、線の描画後に塗りを表示しています。
クラスを付けたときだけ動かす
画面表示と同時ではなく、処理成功時や選択時に動かしたい場合は、クラスを切り替える形が扱いやすいです。
<circle
class="status-circle"
cx="50"
cy="50"
r="30" />
.status-circle {
fill: #4caf50;
opacity: 0;
transform: scale(0.8);
transform-box: fill-box;
transform-origin: center;
}
.status-circle.is-visible {
animation: show-status 0.3s ease forwards;
}
@keyframes show-status {
to {
opacity: 1;
transform: scale(1);
}
}
JavaScript側では、必要なタイミングでクラスを追加します。
const statusCircle =
document.querySelector(".status-circle");
statusCircle.classList.add("is-visible");
JavaScriptで細かい値を直接変更するより、見た目はCSSクラス側へまとめる方が管理しやすい場合があります。
アニメーションを一時停止する
.animated-shape {
animation-play-state: running;
}
.animated-shape.is-paused {
animation-play-state: paused;
}
クラスの追加・削除で一時停止できます。
element.classList.toggle("is-paused");
⚠️ ハマりやすいポイント
回転の中心がずれる
SVG要素へそのまま、
transform: rotate(360deg);
を指定すると、回転の中心が想定と違うことがあります。
まずは、
transform-box: fill-box;
transform-origin: center;
を確認します。
display:none から滑らかに表示できない
display は opacity のように中間状態を持たないため、滑らかなフェードには向きません。
フェードさせたい場合は、
opacity: 0;
visibility: hidden;
から、
opacity: 1;
visibility: visible;
へ切り替える方法が使えます。
線の描画には stroke が必要
stroke-dasharray と stroke-dashoffset は線に対して使うため、対象要素へ stroke を指定します。
fill="none"
stroke="#333"
のようにしておくと分かりやすいです。
transformを複数のアニメーションで上書きしない
例えば回転と拡大縮小の両方で、
transform: rotate(...);
transform: scale(...);
を別々に指定すると、後から適用された方で上書きされることがあります。
同時に使う場合は、
transform: rotate(180deg) scale(1.2);
のようにまとめるか、親子要素に分けて適用します。
動きを減らす設定にも対応する
ユーザーのOS設定でアニメーションを減らしている場合は、動きを停止できます。
@media (prefers-reduced-motion: reduce) {
.blink-circle,
.rotate-shape,
.pulse-circle,
.draw-line {
animation: none;
transition: none;
}
}
装飾目的のアニメーションなら、無効化しても操作に影響しない作りにしておくと安全です。
📝 まとめ
SVGのCSSアニメーションでは、まず次を覚えておけば大体対応できます。
| 動き | 主な指定 |
|---|---|
| 色変更 |
transition / fill / stroke
|
| フェード | opacity |
| 点滅 | @keyframes |
| 回転 | rotate() |
| 拡大縮小 | scale() |
| 線の描画 |
stroke-dasharray / stroke-dashoffset
|
| 状態による開始 | クラスの追加・削除 |
自分の場合、特に忘れやすいのは、
transform-box
transform-origin
stroke-dasharray
stroke-dashoffset
あたりです。
SVGの動きで迷ったときに見返せるよう、ひと通りまとめておきます。