スクロールに合わせたアニメーション、昨今はクライアントさんがぐりぐり動かしたいっ、というケースが増え必須技術になっていますが、レスポンシブで行う場合、スクロール量が変化する為それなりに面倒です。これまで様々なプラグインもありました。「Intersection Observer API」を使うと、効率的にソースを書くことが出来る!!便利だ。ということで、使い回しがしやすいパタンを作っておくことにしました。
Intersection Observer API
Intersection Observer API 「交差監視 API」。要素と、祖先要素または最上位のビューポートとの交差を非同期で監視します。スクロール量計算ではなく、交差したタイミングを取りますので、可視領域に入った時にアニメーションを発動することが出来ます。可視領域から外れた場合の動作指定ももちろん可能です。
交差したら、class名を付与する
アニメーション自体はCSSで作成し、可視領域に入ったら要素にclassを付与、アニメーションが発火する、という使い勝手の良さそうなシチュエーションで試してみました。
※複数個数にアニメーションをつけるために、少し時間をずらしてアニメーションするようにしています。
<script>
const doObserve = (element) => {
const targets = document.querySelectorAll(element);
const options = {
root: null,
rootMargin: "10% 0px",
threshold: [0.2, 1.0], //20%から100%
};
const observer = new IntersectionObserver((items) => {
items.forEach((item, index) => {
if (item.isIntersecting) {
setTimeout(() => {
item.target.classList.add('is-visible')
}, index * 150)
} else {
item.target.classList.remove('is-visible')
}
})
}, options)
Array.from(targets).forEach((target) => {
observer.observe(target)
})
};
doObserve('.hoverGrid'); //監視対象の指定
</script>
後は該当要素に「is-visibleクラス」が付与された場合に、CSSアニメーションを適用するようにCSSを用意します。追加で別のアニメーションを作る場合は「doObserve2」のように名称を変更すればOKです。
Options
IntersectionObserverにはオプションがあります。オプションの指定は、コンストラクタの第二引数にオブジェクトを渡します。
名称 | 値 | デフォルト |
---|---|---|
root | ルート(交差判定のベース)となる要素。rootを指定すると、viewport以外との交差判定ができます。 | viewport |
rootMargin | root要素からの距離です。「マイナス値」を設定するとルート要素の手前で交差を検知します。単位はpxまたは%で指定し、単位をつけて指定します。 | 0px 0px 0px 0px |
threshold | コールバックが呼ばれるタイミング。交差を検知する閾値で、0~1の値を設定することができます。デフォルト0の場合は交差領域が0、つまり重なり始めと重なり終わりに検知されます。 | 0 |
thresholdが少し分かりにくいかな。領域に入った、出た、だけではその間でアニメーションを呼び出すことはできませんが、以下のようにthresholdの引数を設定すると、交差領域が 20% 変化する毎にコールバックを呼ぶことができるようになります。より複雑なインタラクションアニメーションが設定出来るということですね。
{ threshold: [0, 0.2, 0.4, 0.6, 0.8, 1.0] }
IE11への対策
Intesection Observer APIはIE11では対応していませんので、ポリフィルを利用します。<head>内に追加すればOKです。
https://github.com/w3c/IntersectionObserver/tree/master/polyfill
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.js?features=IntersectionObserver"></script>