本文までスキップする
0

読みもの
Journal

【GSAP】どんなSVGでも破綻しないラインアニメーションを実装しよう
Date :
Category :
コラム
Share :

こんにちは、ウィルスタイルの梁川です。

入社から早くも5ヶ月が経ち、毎日多くの学びがある日々を送っています。
既存サイトの保守・更新や下層ページのデザイン、ディレクションの補助など、さまざまな業務を経験させていただき、時間が経つのもあっという間です。

どの業務も楽しんでいますが、個人的な関心としてWeb上でのアニメーションを探求するのが好きです。

今回は、スクロールに合わせて線が描かれるSVGアニメーションの作り方をご紹介したいと思います。
視線誘導やストーリー性を作るうえで、とても効果的な表現です。

実際の挙動や全体のコードは、以下のURLからご確認いただけます。

( Index )

  1. HTML・CSS
  2. 線が描かれる仕組み
      1. アニメーションの原理
  3. JavaScriptでの実装
    1. Step 1:要素の取得とループ処理
    2. Step 2:パスの長さを自動取得
    3. Step 3:初期状態のセット(線を隠す)
    4. Step 4:スクロールアニメーションの設定
  4. 完成アニメーション
  5. おわりに

HTML・CSS

まずは土台となるコードです。いくつかこだわっているポイントだけピックアップします。

<div class="circle__item">
  <svg class="circle__shape" data-circle aria-hidden="true" ...>
    <path stroke="#000" d="..." />
  </svg>
</div>

HTMLでは、JavaScriptのフック用に data-circle というデータ属性を使用しました。クラス名(スタイル用)と分けることで、デザイン変更に強い設計にしています。 また、装飾用の画像なので aria-hidden="true" を付与し、スクリーンリーダーへの配慮も行っています。

.circle__item {
  margin-top: -180px;
}

CSSでは、margin-top にマイナスの値を指定して円の要素を重ねて、連鎖する波紋のような奥行きを表現しました。

線が描かれる仕組み

実装に入る前に、そもそもなぜ線が伸びていくように見えるのか、その原理を整理しておきましょう。 これは、線を伸ばしているのではなく、点線の隙間を移動させているというイメージです。 鍵となるのは、SVGの2つのプロパティです。

  • stroke-dasharray:点線の「実線」と「隙間」の間隔
  • stroke-dashoffset:線の開始位置のズレ

アニメーションの原理

通常、点線は「実線・隙間・実線…」の繰り返しですが、「実線の長さ」と「隙間の長さ」を、パスの全長と同じ長さに設定することで、今回のようなアニメーションが実装できます。

  1. 隠す(初期状態)
    stroke-dasharray で「全長分の実線」と「全長分の隙間」を作ります。
    そして stroke-dashoffset を使って、開始位置を「全長分」ずらします。
    そうすると、画面上では「隙間」の部分だけが表示され、線が見えなくなります。
  2. 描く(アニメーション)
    スクロールに合わせて、ずらしていた stroke-dashoffset0 に戻していきます。
    すると、画面外に押し出されていた「実線」の部分が入ってきて、線が描かれているように見せることができます。

JavaScriptでの実装

仕組みがわかったところで、今回のメインであるJavaScriptの実装です。

Step 1:要素の取得とループ処理

const circles = document.querySelectorAll("[data-circle]");
 
if (circles.length > 0) {
  circles.forEach((el) => {
    const path = el.querySelector("path");
    if (!path) return; // エラー回避
  });
}

まず querySelectorAll で対象となるSVGをすべて取得します。 その後、forEach を使って1つずつ処理を回していきます。こうすることで、ページ内に複数のアニメーションがあっても、それぞれ個別に動作させることができます。 if (!path) return; は、万が一SVG内にパスが含まれていなかった場合にエラーで止まるのを防ぐための記述です。

Step 2:パスの長さを自動取得

// パスの正確な長さを取得
const length = path.getTotalLength();

ここが今回の最大のポイントで、 getTotalLength() メソッドを使うと、パスの正確な幾何学的な長さを取得できます。 これにより、「SVGを差し替えたら線が足りなくなる」といった問題を解消できます。

Step 3:初期状態のセット(線を隠す)

gsap.set(path, {
  strokeDasharray: length,
  strokeDashoffset: length
});

取得した length を使って、CSSプロパティをセットします。 gsap.set で初期状態を指定します。 ここで「線の長さ」と「ズレ」をどちらも全長と同じにすることで、画面上では線が完全に隠れた状態になります。

Step 4:スクロールアニメーションの設定

gsap.to(path, {
  strokeDashoffset: 0, // 0に戻して線を描く
  ease: "none",
  scrollTrigger: {
    trigger: el,
    start: "top center",
    end: "center center",
    scrub: 1,
  }
});

最後に gsap.to でアニメーションを実行します。 strokeDashoffset0 に戻すことで、隠れていた実線部分が画面内に引き戻され、線が描かれていきます。

  • ease: “none”
    デフォルトの「動き出しがゆっくり」などのイージングを解除し、スクロールと等速で描かれるようにします。
  • scrub: 1
    スクロールに追従させます。true ではなく数値を指定することで、ピタッと止まらず「1秒遅れて追いつく」ような余韻が生まれ、リッチな操作感になります。

完成アニメーション

完成したものがこちらです。 正確な長さを取得しているため、最後まで気持ちよく線が描かれています。

おわりに

いかがだったでしょうか。 今回は「getTotalLength」を活用して、メンテナンス性の高いSVGラインアニメーションを実装しました。 一度仕組みを作ってしまえば、ロゴや手書き文字など、あらゆるSVGアニメーションに応用が効きます。ぜひプロジェクトに取り入れてみてください。

  • Author
    Takuma Yanagawa