スクロールに連動したSVGパス描画アニメーションの作り方
スクロールを進めると、SVGの曲線が徐々に描画されるアニメーションの実装方法を解説しています。GSAPを使うと意外と少ないコードで実装できます。
実装例
早速ですが以下が実装例です。
下方向にスクロールすると曲線が徐々に描画され、上方向にスクロールすると曲線が徐々に消えていくことが確認できます。
絶対配置した画像やカード要素を曲線で繋ぐことで、ユーザーの注目を集める演出が可能です。Lenis等のスムーズスクロールライブラリで実装した慣性スクロールとの相性も良いように感じます。
コードの解説
HTMLではdata-draw-stroke属性を付与したラッパーの中にSVGを配置しています。SVGの曲線はpath要素で定義しています。
<div data-draw-stroke> <svg fill="none" height="1979" viewBox="0 0 1317 1979" width="1317"> <path d="M380 40 C50 200 900 150 600 400 C300 650 1000 700 700 950 C400 1200 50 1150 300 1400 C600 1650 1200 1500 900 1750 C650 1950 200 1850 350 1700" stroke="#222" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg></div>JavaScriptの処理
事前にGSAP本体とScrollTriggerを読み込んでいます。コードの全体像は次の通りです。
// 対象要素の取得const triggers = document.querySelectorAll("[data-draw-stroke]");const paths = document.querySelectorAll("[data-draw-stroke] svg path");
// 各要素ごとに処理triggers.forEach((triggerEl, index) => { const path = paths[index];
// パスの全長を取得 const pathLength = path.getTotalLength();
// 初期状態:線を完全に隠す gsap.set(path, { strokeDasharray: pathLength, strokeDashoffset: pathLength, });
// ScrollTriggerで描画アニメーション ScrollTrigger.create({ trigger: triggerEl, start: "top center", end: "bottom 70%", markers: false, // 進捗に応じて線を描画 onUpdate: (self) => { // 0~1の値の進捗度合い const progress = self.progress; // 線を徐々に描画 path.style.strokeDashoffset = pathLength * (1 - progress); }, });});大きく分けて3つの処理を行なっています。
- パスの全長を取得
- 初期状態で線を完全に隠す
- スクロールの進捗度合いとパスの開始位置を同期
パスの全長を取得
path要素のgetTotalLength()メソッドを使用して、パスの全長を取得しています。
const pathLength = path.getTotalLength();初期状態で線を完全に隠す
gsap.set()メソッドを使用して、初期状態で線が表示されないようにしています。
gsap.set(path, { strokeDasharray: pathLength, strokeDashoffset: pathLength,});strokeDasharray: 破線パターンの長さstrokeDashoffset: パスの描画開始位置
stroke-dasharrayでパス全長の破線を作り、stroke-dashoffsetをパスの長さ分ずらすことで描画/非表示を切り替えています。SVGのパスを使用したアニメーションでよく使われるテクニックです。
両者の関係を図で表すと次のようになります(パスの全長を400pxと仮定)。
スクロールの進捗度合いとパスの開始位置を同期
スクロールの進捗度合いを取得するために、onUpdateのコールバック関数を使用しています。
ScrollTrigger.create({ trigger: triggerEl, start: "top center", end: "bottom 70%", markers: false, onUpdate: (self) => { const progress = self.progress; path.style.strokeDashoffset = pathLength * (1 - progress); },});onUpdate関数の中でself.progressにアクセスすることで、スクロールの進捗度合いを取得することができます(0~1の値)。
(1 - progress)ではスクロールの進捗度合いを反転させ、その値にパスの全長を掛けることで、曲線を描画するためのオフセット(パスの開始位置)を計算しています。そして算出された値をstrokeDashoffsetプロパティに代入し曲線を描画しています。
まとめ
GSAPのScrollTriggerを使用して、スクロールに連動したSVGパス描画アニメーションを実装しました。
仕組みとしてはstroke-dasharrayとstroke-dashoffsetでパスの表示範囲を制御し、スクロールの進捗に応じてオフセットを変化させることで線が描かれていく表現を実現しています。
SVGのパスの形状を変更すれば、要素同士を曲線で繋ぐ演出やタイムライン風のレイアウトなど、様々な表現に応用できそうです。
