SVGストロークアニメーションの作り方|線画が描かれる演出をCSSとJavaScriptで実装|初心者向け


はじめに

Webデザインにおいて、視覚的なインパクトを与えるアニメーションは非常に効果的です。その中でもSVGを使用したストロークアニメーションは、軽量でスムーズな動きが特徴で、ユーザー体験を向上させることができます。本記事では、SVGのストロークアニメーションをCSSだけで作る方法JavaScriptでパス長を正確に取得する方法を、そのままコピーして動くコード付きで解説します。


ストロークアニメーションとは?

SVGストロークアニメーションとは、stroke-dasharraystroke-dashoffset の2つのプロパティを使い、線が手で描かれていくように見せるSVGの演出技法です。パスを「破線」として扱い、その破線をずらして隠した状態から元に戻すことで、線が徐々に現れるエフェクトを作ります。CSSだけでも、JavaScriptでパスの全長を取得しても実装できます。

差分チェックツールで効率UPお手本コードと自分のコードを比較して、違いを一目で確認できます。練習前にブックマークしておくと便利です。
Diff Checkerを開く →

See the Pen Untitled by masakazuimai (@masakazuimai) on CodePen.


仕組み:stroke-dasharray と stroke-dashoffset

仕組みはシンプルです。まず stroke-dasharrayパスの全長以上の値を指定して、線全体を「1本の長い破線」として扱います。次に同じ値を stroke-dashoffset に入れると、破線が丸ごとずれて線が消えた状態になります。あとはこのオフセットを 0 に向けてアニメーションさせれば、線が描かれていくように見えます。

.path {
  stroke-dasharray: 1000;   /* 線全体を1本の長い破線として扱う */
  stroke-dashoffset: 1000;  /* 破線を全部ずらして“消した”状態にする */
  animation: draw 3s ease forwards;
}

@keyframes draw {
  to { stroke-dashoffset: 0; } /* 0に戻す=線が描かれていく */
}

CSSのみで実装する場合に必要な「パスの全長」は、ブラウザの開発者ツールのコンソールで次の1行を実行するとすぐ確認できます。ここで得た値を stroke-dasharray に使えば、無駄な概算を避けられます。

// DevToolsのコンソールで実行するとパスの全長が分かる
document.querySelector('.draw-path').getTotalLength();

関係するプロパティを整理すると次のとおりです。

プロパティ役割
stroke-dasharray線を破線パターンにする。全長以上の1値を指定して「まだ描かれていない」状態を作る
stroke-dashoffset破線の開始位置をずらす。全長→0でアニメーションさせると「描かれていく」動きになる
stroke-linecap線の端の形状を決める(butt / round / square)
vector-effect: non-scaling-stroke拡大縮小しても線幅を一定に保つ(レスポンシブで有効)

CSSだけで実装する(コピペ可)

もっとも手軽なのはCSSだけで完結させる方法です。SVGのパスにクラスを付け、stroke-dasharraystroke-dashoffsetパスの全長以上の固定値を入れてアニメーションさせます。まずはHTML(SVG)です。

<svg viewBox="0 0 200 100" width="200" height="100">
  <path d="M10 50 Q 60 10, 110 50 T 190 50"
        fill="none" stroke="#4f46e5" stroke-width="4"
        stroke-linecap="round" class="draw-path" />
</svg>

続いてCSSです。このまま貼り付ければ、ページ読み込み時に線が描かれます。

.draw-path {
  stroke-dasharray: 300;    /* パスの全長以上の固定値を指定 */
  stroke-dashoffset: 300;   /* 同じ値でいったん線を隠す */
  animation: draw 2.5s ease-out forwards;
}

@keyframes draw {
  to { stroke-dashoffset: 0; }
}

注意点は stroke-dasharray の値です。パスの実際の全長より小さいと線の途中で止まり、大きすぎると描き始めに間(ま)ができます。パスを変えるたびに数値を調整する必要があるのがCSSのみの弱点で、これを自動化したいときは次のJavaScriptの方法が便利です。


JavaScriptでパス長を正確に取得する

パスの全長を手で測らずに済ませるには、getTotalLength() を使います。パスの正確な長さを取得して stroke-dasharraystroke-dashoffset に設定するので、パスを変更してもコードを直す必要がありません。

const path = document.getElementById('logo');
const length = path.getTotalLength();   // パスの全長を正確に取得

path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;

path.getBoundingClientRect();            // 再描画を強制(オフセット反映のため)
path.style.transition = 'stroke-dashoffset 2.5s ease-out';
path.style.strokeDashoffset = '0';       // 0に向けて線を描画

CSSのみとJavaScript制御は、それぞれ向き不向きがあります。用途で選びましょう。

観点CSSのみJavaScript(getTotalLength)
パス長の指定全長以上を手動で概算自動で正確に取得
パス変更への追従都度dasharrayを再調整コードがそのまま追従
発火タイミング読み込み時・hoverなどスクロール連動・任意のイベント
複数パスの順次描画delayを手計算ループで自動化できる
向いている場面単純な1パスの装飾ロゴ署名・スクロール演出・複数パス

このアニメーションの特徴

このストロークアニメーションは以下のような特徴を持っています:

  1. 軽量
    SVGはベクター形式で記述されるため、画像形式よりも軽量で高解像度を維持できます。
  2. 滑らかな動き
    CSSトランジションを使用することで、ストロークが描画される様子をスムーズに表現しています。
  3. カスタマイズ性
    色や線の幅、アニメーション速度を簡単に調整できるため、様々なデザインに応用可能です。

どんな場面で使える?

このようなアニメーションは、以下のようなシーンで効果を発揮します:

  • ローディング画面
    ページやコンテンツが読み込まれる間に表示されると、待機時間が短く感じられます。
  • アイコンの強調
    特定の操作を促すボタンやアイコンの周囲に動きを与えることで、視覚的な注意を引きつけることができます。
  • インタラクティブな要素
    ホバーやクリック時にアニメーションを発動することで、ユーザーとのインタラクションを強化します。

実務Tips(ベストプラクティス集)

複雑すぎるパスを避ける

SVGパスが極端に複雑だと、アニメーションがカクついたり描画負荷が高くなります。必要に応じてIllustratorやFigmaでアンカーポイントを減らし、パスを最適化しましょう。

カクつきは will-change で抑える

アニメーション対象に will-change を指定すると、ブラウザが描画を最適化しやすくなり、カクつきを軽減できます。多用は禁物ですが、主役のパスに限定して使うのが効果的です。

.draw-path {
  will-change: stroke-dashoffset; /* 描画を最適化してカクつきを抑える */
}

複数のパスを順番に描画する

ロゴや文字など複数のパスを順番に描きたいときは、各パスの全長を取得し、animation-delay を少しずつずらします。JavaScriptならループで自動化できます。

document.querySelectorAll('.draw-path').forEach((p, i) => {
  const len = p.getTotalLength();
  p.style.strokeDasharray = len;
  p.style.strokeDashoffset = len;
  p.style.animation = `draw 2s ease forwards ${i * 0.4}s`; // 0.4秒ずつ遅らせる
});

レスポンシブは vector-effect で線幅を保つ

SVGは拡大縮小に強いですが、viewBox を必ず設定し、固定幅を避けて width="100%" を使うと崩れにくくなります。さらに vector-effect: non-scaling-stroke を指定すると、拡大しても線幅が太くならず一定に保てます。

prefers-reduced-motion でアクセシビリティに配慮する

動きを抑えたいユーザー向けに、prefers-reduced-motion でアニメーションを無効化し、完成形を即座に表示する分岐を入れておくと親切です。

@media (prefers-reduced-motion: reduce) {
  .draw-path {
    animation: none;        /* アニメーションを無効化 */
    stroke-dashoffset: 0;   /* 完成形を即表示 */
  }
}

フォールバックを用意する

ごく一部の環境ではSVGアニメーションが意図通り動かないことがあります。重要な情報を線画だけに頼らせず、静的なSVG/PNGでも内容が伝わるようにしておくと安全です。


うまく描画されないときのチェックリスト

ストロークアニメーションが思いどおりに動かないときは、原因の多くが次の5つに集約されます。上から順に確認すると早く解決できます。

  • 線が途中で止まる → stroke-dasharray がパスの全長より小さい。全長以上の値(迷ったら getTotalLength() の値)を入れる。
  • 塗りつぶされて線画に見えない → pathfill="none" が無い。塗りが残ると描画演出が見えない。
  • アニメーション後に線が消える → animationforwards が無い。最終状態を保持するには forwards を指定する。
  • そもそも線が見えない → strokestroke-width が未指定。色と太さを必ず指定する。
  • 描き始めに不自然な間ができる → stroke-dasharray が全長より大きすぎる。全長に近い値へ調整する。

応用と次の一手

ここまでの仕組みは、ロゴの「署名のように描かれる」演出、ローディングインジケーター、アイコンの強調など、幅広く応用できます。まずは1パスのCSS実装で動きを掴み、複数パスやスクロール連動が必要になったらJavaScript制御へ広げる、という順番がおすすめです。

次の一手として、動いているコードをそのままAIに渡して改造する方法があります。色・速度・対象要素だけを差分で指示すれば、ゼロから生成させるより速く確実です。詳しくは CSSアニメーションはAIに「コードを渡して」作る で解説しています。


よくある質問

Q. ストロークアニメーションに必須のプロパティは?

A. 基本は stroke-dasharraystroke-dashoffset の2つです。これらをアニメーションさせることで「線が描かれる演出」を作れます。

Q. パスの長さはどうやって取得しますか?

A. JavaScriptの getTotalLength() メソッドで正確に取得できます。取得した値を stroke-dasharraystroke-dashoffset に設定するのが定番です。

Q. CSSだけで実装できますか?

A. はい、単純なアニメーションならCSSだけで可能です。stroke-dasharray にパスの全長以上の固定値を入れれば動きます。複雑な制御や複数パスの調整にはJavaScriptが便利です。

Q. レスポンシブ対応にする方法は?

A. viewBox を設定し、固定幅を避けて width="100%" を指定します。線幅を一定に保ちたいときは vector-effect: non-scaling-stroke も有効です。

Q. アニメーションがカクつくのはなぜ?

A. パスのアンカーポイントが多すぎる場合や描画処理が重いとカクつきます。パスの簡略化、イージング調整、will-change の指定を検討してください。

Q. ロゴアニメーションにも使えますか?

A. はい、特にロゴやアイコンに「描かれる」演出をつけるとブランディング効果が高まります。複数パスを順番に描画すると、より手書きらしい仕上がりになります。


参考リンク

本記事のプロパティ・メソッドの仕様は、MDN Web Docsの公式ドキュメントに基づいています。


まとめ

SVGストロークアニメーションは、stroke-dasharraystroke-dashoffset の2つだけで「線が描かれる」演出を作れる、軽量で応用範囲の広い手法です。まずはCSSだけのコピペ実装で動きを確認し、パスの変更に追従させたい・複数パスを順番に描きたいときはJavaScriptの getTotalLength() へ広げましょう。will-changeprefers-reduced-motion まで押さえれば、実務でそのまま使える品質になります。