4. 線が描かれていくアニメーションを実装する
ここからが本題です。線が手書きで描かれていくように見せる仕組みは、SVGのstroke-dasharrayとstroke-dashoffsetという2つのプロパティを使います。
stroke-dasharray:パスを破線にするプロパティ。パスの全長以上の値を指定すると、実質「実線→透明」の2区間だけの破線になる
stroke-dashoffset:破線の開始位置をずらすプロパティ。パスの全長分ずらすと、線が完全に見えない状態になる
つまり、stroke-dashoffsetをパスの全長 → 0まで変化させると、線がじわじわと描かれていくように見える、という仕組みです。
パスの全長は、固定値を手入力する必要はなく、JSのgetTotalLength()で動的に取得できます。
const stroke = document.querySelector('#stroke');
const length = stroke.getTotalLength();
stroke.style.strokeDasharray = length;
stroke.style.strokeDashoffset = length;
ここからstroke-dashoffsetを0まで変化させる方法として、今回は2パターンご紹介します。
方法①:Web Animations API(ライブラリ不要)
ブラウザ標準のElement.animate()(Web Animation API)を使えば、追加ライブラリなしでstroke-dashoffsetをアニメーションできます。
const stroke = document.querySelector('#stroke');
const length = stroke.getTotalLength();
stroke.style.strokeDasharray = length;
stroke.style.strokeDashoffset = length;
stroke.animate(
[
{ strokeDashoffset: length },
{ strokeDashoffset: 0 }
],
{
duration: 4000,
easing: 'ease-in-out', // 'cubic-bezier(...)' で細かい指定も可能
fill: 'forwards'
}
);
- ライブラリ不要で軽量
- 戻り値の
Animationオブジェクトで.pause() / .play() / .reverse() / .finished(Promise)といった制御ができる
- イージングはCSSのイージング関数(
ease / cubic-bezier() / steps()など)の範囲に限られる
- 複数パスを順番に描く・スクロールに連動させるといった複雑な制御は自分で組む必要がある
ロゴのワンポイント演出のように、1〜数本のパスをワンショットで描くだけならこれで十分なケースが多いです。
以下のデモでは、手書きのストロークをいくつかに分割した上で、順番に描画する処理を行っています。
それぞれのストロークのアニメーションは完了後に commitStyles() でstyle属性として書き込んで固定した後にcancel()で削除しています。アニメーションは静的なスタイルよりも優先されるため、こうしておくことで状態をリセットして再度アニメーションをさせたい場合などに不具合が起こりにくいです。
方法②:GSAP + DrawSVGPlugin
複数の文字・複数行を順番に描いたり、スクロールに連動させたり、緩急の効いたイージングを使いたい場合は、GSAPのDrawSVGPluginが便利です。
GSAPにはDrawSVGPluginをはじめとした拡張プラグイン(MorphSVGPlugin・SplitTextなど)が用意されており、こうした複雑な描画アニメーションも簡潔に書けるようになっています。
import { gsap } from 'gsap';
import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin';
gsap.registerPlugin(DrawSVGPlugin);
gsap.set('#stroke', { drawSVG: '0%' });
gsap.to('#stroke', {
drawSVG: '100%',
duration: 4,
ease: 'power2.inOut'
});
drawSVGは内部でstroke-dasharray / stroke-dashoffsetを操作してくれるので、getTotalLength()やstroke-dasharrayの手動設定すら不要です。緩急の効いたイージングもease: 'power2.inOut'の一行で指定できます。
複数行・複数パスを順番に描きたい場合は、タイムラインやstaggerを使うと簡潔に書けます。
gsap.timeline()
.from('.stroke-line1', { drawSVG: '0%', duration: 2, ease: 'power1.inOut' })
.from('.stroke-line2', { drawSVG: '0%', duration: 2, ease: 'power1.inOut' }, '-=0.5'); // 少し重ねて開始
// あるいは複数パスをまとめてstagger再生
gsap.from('.stroke', {
drawSVG: '0%',
duration: 2,
ease: 'power1.inOut',
stagger: 0.3
});
最初にWeb Animation APIで実装したデモをGSAPを使って書き換えたものがこちらになります。
さらに、スクロールに合わせて文字を描かせたい場合は、ScrollTriggerと組み合わせるだけです。
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(DrawSVGPlugin, ScrollTrigger);
gsap.from('#stroke', {
drawSVG: '0%',
ease: 'none',
scrollTrigger: {
trigger: '#stroke',
start: 'top 80%',
end: 'top 30%',
scrub: true
}
});
どちらを選ぶか
|
Web Animations API |
GSAP + DrawSVGPlugin |
| 導入コスト |
不要(ブラウザ標準) |
ライブラリ読み込みが必要 |
| 記述量 |
やや多め(getTotalLength等を自分で書く) |
少ない(drawSVGが長さ計算を内包) |
| イージング |
CSSイージング関数のみ |
GSAP独自の豊富なイージング・カスタムイージング |
| 複数パスの連携・スクロール連動 |
自前実装 |
タイムライン・stagger・ScrollTriggerで簡潔に書ける |
| 向いているケース |
ワンショットで1〜数本描くだけ |
複数文字・複雑な順序・スクロール演出・凝った緩急 |
ロゴのワンポイント演出くらいならWeb Animations APIだけで十分ですが、サイト全体の複数箇所で使う、スクロールに連動させる、といった要件があるならGSAPを利用した方がコードとしてはシンプルに書けるという印象です。