【CSS + JS】テキストの無限ループアニメーション
Intersection Observerを使って
画面内に要素が入ったら
アニメーションさせる
目次
はじめに
画面スクロール時に特定の要素が画面内に入ったら読み込んだり、アニメーションを適用して表示させたりしたい時に使えるAPIのメモ。
こういった実装はこれまでscroll
イベントで実装されてきましたが、スクロールするたびにイベントが発生するので負荷がかなり大きく、画面が重くなる原因になりがちでした。そのためrequestAnimationFrame
を使ってパフォーマンスを向上させる方法などがググるとたくさん紹介されています。それでもまだ重く感じたり負荷が気になっていたのですが、それを解決する「Intersection Observer API」というものがあることを知ってからはこちらで実装するようになりました。
Intersection Observer APIとは?
直訳すると「交差点監視」という意味ですが、その名の通り「要素同士の交差を判定できる」APIです。指定した要素と要素が交差した時だけイベントが発生するので、これまでのようにスクロールするたびに画面のスクロール位置を取得して目標の要素の位置や高さを取得して条件分岐して・・・というスクロールイベントの闇から解放されます。笑
対応ブラウザ
IEなど一部のブラウザで使えませんが、Edge、Chrome、Firefox、Safari、iOS Safariなどのモダンブラウザの最新バージョンで使えます。もちろんpolyfillがありますので、対応していないブラウザにも対応可能です
使い方
//オプション指定
const options = {
//要素の見えている割合が20%を超える度にコールバックを実行
threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
}
//交差した時に発生するコールバック
const callback = (entries, observer) => {
entries.forEach(entry => {
//交差している領域の割合が20%を超えた場合
if (entry.intersectionRatio > 0.2) {
//アニメーションや画像の読み込みなどの処理
}
});
}
//IntersectionObserverをインスタンス化
const observer = new IntersectionObserver(callback, options);
//監視する要素の配列を取得
const observers = [...document.querySelectorAll('.js-event')];
//配列に指定した要素をIntersectionObserverで監視
observers.forEach(el => {
observer.observe(el);
});
基本的にはこれだけです。コールバックの処理を書く以外にはほとんど何も必要ありません。ただ細かく制御したい場合は以下のポイントを変更すればOKです。
オプション指定
//オプション指定
const options = {
// ルートとして指定する要素。省略するとデフォルトはviewport
root: document.querySelector('.root'),
// 交差する上下左右100px手前で発火させることができる
rootMargin: "100px",
//要素の見えている割合が20%を超える度にコールバックを実行
threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
}
root
については基準にしたい要素を指定します。
rootMargin
は交差する前にイベントを発生させたい場合に使います。画像の遅延読み込みなんかはこれを使うと画面に入ってくる直前に読み込みできるので便利かもしれませんね。
threshold
はイベントの発生するタイミングを調整できます。例のように配列で指定すると、指定した要素が画面に0%入った時、20%入った時、40
%入った時、60%入った時、80%入った時、100%入った時の計6回、交差している間にコールバックイベントを発生させます。
こちら例として配列を使いましたが、僕は基本的に複数回発生させる処理は不要なので、0.2とか0.5とか配列でなくそのまま数値で指定して1回だけ発生させています。
コールバック
//交差した時に発生するコールバック
const callback = (entries, observer) => {
entries.forEach(entry => {
//交差している領域の割合が20%を超えた場合
if (entry.intersectionRatio > 0.2) {
//アニメーションや画像の読み込みなどの処理
}
});
}
ここではentry.intersectionRatio
という部分で、イベント発生した時に交差している割合を取得できるのでそれを使って処理を分岐しています。
他にもイベント発生時に以下のような情報を取得できます。
boundingClientRect
:イベント発生した要素の座標位置intersectionRect
:交差領域の座標位置isIntersecting
:イベント発生時に交差しているかどうかisVisible
:イベント発生時に要素がすべて見えているかどうか(?)rootBounds
:ルート要素の座標情報target
:イベント発生した要素time
:タイムスタンプ
簡単なデモ
とりあえず簡単なデモを作ってみました。(IE対応はしていません)
DEMO
偶数の番号が書いてある要素が画面内に要素の20%が交差すると背景が黒に変わるアニメーションを付けてみました。
具体的にはコールバック関数に以下を追加しただけのシンプルな実装です。
if (entry.intersectionRatio > 0.2) {
//クラスを追加
entry.target.classList.add('is-effect');
}
クラスの付け替えでCSSアニメーションを発生させることができますね。ここではtransition
を使いましたが、もっと複雑な動きならanimation
を使った方が良いかもしれません。
さいごに
Intersection Observer APIについてサクッとメモしました。
今までスクロールイベントの負荷で困っていた方や気になっていた方は有効なので使ってみてください。
RELATED
NEW POSTS
【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた
【netlify】ビルドイメージを更新 [ Ubuntu Xenial 16.04 → Ubuntu Focal 20.04 ]
【PHP】Google Business Profile APIを使ってクチコミを取得する
スクリーンショットのAPI「screendot」を使ってみた
【window.matchMedia】メディアクエリでhoverが使えるデバイスを判定
lax.jsの使い方【スクロール連動アニメーションの実装】