Help us understand the problem. What is going on with this article?

使ってみよう!Intersection Observer!

More than 1 year has passed since last update.

1)はじめに

スクロールに追従して、

  • 画像の遅延ロード
  • YouTubeの自動再生
  • コンテンツの追加読み込み

といったことを行いたい。
このようなケースにおいて、今まではスクロールイベントをフックとして実装することがほとんどでした。しかし、頻繁に実行されるスクロールイベントは、ブラウザにとって優しい処理とは言えず、特にスマホではスクロール詰まり(Scroll Jank)を引き起こしてしまうこともありました。

そこで登場する、比較的新しいAPIがIntersection Observerです。
今回はその利用方法について模索してみます。

2)Intersection Observerとは

その名の通り「Intersection(要素間交差)」を「Observe(監視)」するAPI。
任意の要素(DOM)同士の交差を監視することが出来ます。
デフォルトでviewport(見えている範囲)とある要素が交差=ある要素が見えたら何かする、というものです。

// オプション
const options = {
    // ルートとして指定するDOM(無ければviewport)
    root: document.querySelector('.root'),

    // 上下100px、左右20px手前で発火
    rootMargin: "100px 20px",

    // 交差領域が50%変化するたびに発火
    threshold: [0, 0.5, 1.0]
};

/// 初期化
const observer = new IntersectionObserver(callback, options);

targets.forEach(function(img) {
    // 監視の開始
    observer.observe(img);
});

// コールバック
function callback(entries, object) {
    entries.forEach(function(entry, i) {
        // 交差していない
        if (!entry.isIntersecting) return;

        // ターゲット要素
        const img = entry.target;

        // 遅延ロードなど、行いたいことの処理
        loading(img);

        // 監視の解除
        object.unobserve(img);
    });
};

root(任意)

デフォルトではdocumentすなわちviewport。
見えている範囲とターゲットが交わる(すなわち可視状態にある)時に動作している。
これを変更することで別ターゲットと交わった際の動作を指定できる。

rootMargin(任意)

指定についてはCSS同様。上記の例では上下100px、左右20px手前でイベントが発生する。
画像の遅延ロードを行う際有効で、例えば【rootMargin: '500px 0px 0px 0px'】と指定すれば、要素が現れるより500px先に画像のロードが始まることになり、画像の遅延ロード本来の違和感を少なくすることが出来る。

threshold(任意)

例のように【threshold: [0, 0.5, 1.0]】とすれば、交差領域が50%変化するたびにコールバックすることが出来る。

3)対応ブラウザについて

26dd27a3b683782747c7893fc4be82d2.png
Can I use:IntersectionObserver
IE11、iOS Safariは全滅。Edgeは16移行対応となっています。
割と新し目のAPIとは言え、IE11やiPhoneを切ることはなかなか厳しいのではないかと思います。

そこで、下記のDEMOを参考に、Intersection Observer未対応のブラウザにはPolyfill(新しい技術を使えない古いブラウザでも代替の手段を使って同等の効果を得るための拡張)で対応してみたいと思います。

Lazy Image Loading (Using Intersection Observer API [including polyfill])

例えば画像の遅延ロードで言えば、古いブラウザであっても画像が見えないとあっては大問題なので、Polyfillを用いて古いブラウザであっても同等の効果を得ようというのです。

4)様々なDEMO

画像の遅延ロード以外のDEMOをあまり見かけないので、実用的かもしれないDEMOを、Polyfillありなしで作成してみました。

(Polyfillあり)のDEMOについては、IE11、iOS Safari(Desktop/iPhone)でも問題なく動作していることがわかります。iPhoneやIE11のシェアを考えるに、当面の間はPolyfillありのものを使った方が良さそうです。

5)参考リンク

なお、過去の記事などでPolifillのURLをhttps://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill
と紹介いるものが多いが、これは現在404となっている。
今回のDEMOに内包したMinifyしたPolifillは、下記のものを利用している。
https://github.com/w3c/IntersectionObserver

6)おまけ

「要素が見えたら何かする」JavaScriptについて色々調べてみましたが、「Lozad.js」
ってやつが何気に良さそうでした。

GitHub - ApoorvSaxena/lozad.js: 🔥 Highly performant, light ~0.8kb and configurable lazy loader in pure JS with no dependencies for responsive images, iframes and more

俺的LazyLoadの決定版、Lozad.jsを紹介する - Qiita

Intersection Observerを使いやすくした軽量なJSで、Polyfillを使えば未対応ブラウザでも使用可能、画像、iframeの遅延ロードもお手軽にできそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした