要素が画面内に表示されたらアニメーション、IntersectionObserver。

〽️ 画面の外で終わってる! 〽️ IntersectionObserverとは? 〽️ コードを書いていきましょう。 〽️ entriesのプロパティ。 〽️ options。 〽️ アニメーションいきます。 〽️ 全コードはこちら。





⬆︎SVGついてのまとめページ、CSSアニメーションの基本コーナーはこちら。



画面の外で終わってる!


こんにちは、「ふ」です。
webページを彩るCSSアニメーション。みなさん作っていますか? webページはスクロールしながらユーザに閲覧されます。スクロールして、要素が画面内に表示されたタイミングでアニメーションを発火させたい、と思ったことはないでしょうか。

しかし普通にコードでアニメーションを仕込んだだけだと、ページがload(読み込まれた)時点で発火してしまいます。 繰り返し続けるものであれば問題ないのですが、1回こっきり動かしたい場合はどうでしょう。ユーザが対象の要素を画面に表示させた時には、アニメーションが終了してしまっています。

今回はJavaScriptの「IntersectionObserver」というAPIを使って、「要素が画面に表示されたタイミングでアニメーションを発火させる」仕組みを作ってみたいと思います。 コードは簡素なものなので、頑張っていきましょう!

◼︎ コード全体を見たい方は画面右上のmenuボタンから、「全コードはこちら」をクリックしてページ最下部にジャンプしてくださいね。





 

IntersectionObserverとは?


ずいぶん長い名前で、小難しい印象ですが・・ 「intersect」は「横切る、交差する」、observerは「監視人」といった意味です。

発火させたいアニメーション要素(子要素)がviewport〜デバイスの画面(親要素)と交差したかどうかを監視するのが、IntersectionObserverの役割です。

子要素と親要素が重なったときに、実行したい関数を呼び出すことができます。

子要素(アニメーションさせたい要素)と親要素(デバイスの画面)が重なっているということは、これ即ち「要素が画面内に表示されている」状態ですね。そのとき呼び出す関数に、アニメーション発火の処理を仕込めばいいというわけです。





 

コードを書いていきましょう。


経過が観察しやすいように、HTMLとCSSでこんなのを作っておきます。
ページが表示された時点ではお目当ての画像は画面外になるよう、上の<div>〜</div>をバカデカくしておきましょう。

◼︎detayo.svg(お目当ての画像)

◼︎HTML

画像はJavaScriptで取得できるよう、id名をつけておきます。

◼︎CSS

#space { background-color:aqua; height:130vh; }


◼︎ブラウザ


現在このようになっています。画面を下へスクロールしないと画像が見えない状態です。

◼︎ Scriptを記述。

アニメーションを仕込む前に、簡単な関数を使ってIntersectionObserverを試してみましょう。 以下JavaSctiptの記述です。

function kantan() { alert("出たよ〜"); } ;

「出たよ〜」とアラートするだけの簡単な関数です。画像も取得しておきます。

var gazou = document.getElementById("detayo");

扨(さて)ここからIntersectionObserver(←もう略したい)を書いていきましょう。
まづはインスタンスを生成。第1引数には呼び出したい関数を指定できます。

var observer = new IntersectionObserver「「1(kantan)」」;

⬆︎コンストラクタのキャメル表記に注意してください。sectionの「s」は小文字です。
生成したインスタンスに、observeメソッドを使って監視対象の要素を指定します。先ほど取得した「gazou」ですね。

observer.observe「「1(gazou)」」;

以上4行の記述で基本形はできました。実行してみます。

◼︎ブラウザ


ありゃま。

まだ画像が画面内に入っていないのに、ページがロードされた段階でアラートが出てしまっています。これはどういうことなのでしょうか・・





 

entriesのプロパティ。


原因。

IntersectionObserverはデフォルトの設定では、ページ読み込み時に関数を呼び出してしまう仕様になっているのです。子要素と親要素が交差してもいないのに、です。

これを解消するには、Inter〜(←もう略します)に用意されている、「entries」のプロパティを使います。

「entries」は正しくはIntersectionObserverEntryというこれまた長〜い名前のインターフェイスで、親要素と子要素の「交差している部分」の情報を所持しています。

function kantan 「「1(entries)」」 { } ;

呼び出される関数の第1引数に「entries」と記述することで、その内容を取得することができます。
試しに出力してみます。

function kantann (entries) { 「「1console.log(entries);」」   「「3▶︎ [IntersectionObserverEntry]」」 } ;

ちゃんと取得できていますね。
ところで出力されたものが [ ] で囲まれているのにお気づきでしょうか。
今回監視のターゲットとしている要素は1つですが、複数のものが対象になっている場合にはそれぞれの共通部分に関する情報が配列のようにまとめられて返されてきます。ですから [ ] で囲まれているのですね。
したがってターゲットが1つの場合でも、パラメータを取得したい場合には

enties[0].〜

と配列要素を取得するときのように記述します。

そして今回使うのはentriesのintersectionRatioプロパティです。直訳すると「交差の比率」。



ページ読み込み時には、「交差の比率」は「0」です。呼び出される関数の内容を書き換えます。if文を使ってページがロードされたとき、即ち「交差の比率が0」の場合には関数を呼び出さないよう指定しましょう。

function kantan「「1(entries)」」 { 「「1if (entries[0].intersectionRatio == 0) { return; }」」 else { alert("出たよ〜"); } } ;


◼︎ブラウザ


結果を見てみます。ページ読み込み時はアラートは出なくなりました。

画像が画面に重なった段階ではじめてアラートが出ます。成功ですね。





 

options。


ここでもうひとつ手を加えます。現在の状態では、要素がわずかでも画面と交差すると関数が実行されてしまいます。
画像が100%画面内に表示されてからアニメーションを発火させたい。それにはInter〜にこれまた用意されている「options」オブジェクトで指定しましょう。

var observer = new IntersectionObserver(kantan,「「1options」」)」」;

optionsオブジェクトは、親要素と子要素が「交差しているかどうか」の判断基準を制御することができます。

先ほどInter〜のインスタンスを生成しました。コンストラクタの第1引数には呼び出される関数を指定しましたね。
optionsオブジェクトを参照させるには、第2引数として「options」を追加します。

var options = { 「「1threshold:1」」 } ;

optionsの内容を記述します。「threshold」(境界、しきい値)という項目が用意されているのですが、これは「要素同士がどの程度重なり合っている時点で『交差している』と判断し、関数を呼び出すか」を指定するものです。

指定範囲は0 〜 1で、デフォルトでは「0」となっています。「0」だと、要素同士が1pxでも重なっていると「交差した」と判断され関数が呼び出されてしまいます。
これを最大値の「1」に指定しましょう。

◼︎ブラウザ


では再度実行。現在画像は半分しか画面に入っていません。この状態では関数も呼ばれていません。

画像が100%表示された時点でアラートが出るようになりました。

 

アニメーションいきます。


いよいよアニメーションを仕込んでいきましょう。
以前の記事⬇︎で紹介した、「不透明度を0 → 100」にするものをやってみたいと思います。

今回の画像のidは「detayo」でしたね。アニメーション発火に使うクラス名を「alpha」とし、CSSを書いていきます。

◼︎CSS

「「3//画像の初期状態は完全透明」」 #detayo { 「「1opacity:0;」」 } .alpha { animation:alpha 3s; 「「3//アニメーション完了後は不透明になった状態を維持」」 「「1animation-fill-mode:forwards;」」 } @keyframes alpha { 0% { opacity:0; } 100% { opacity:1; } }

画像の初期状態は完全な透明にし、発火すると徐々に不透明度を上げていきます。
完了後は不透明になった状態を維持したいので、アニメーション前後の状態に関するプロパティ「animation-fill-mode」、これを「forward」に指定しました。

◼︎JavaScript

function kantan(entries) { if (entries[0].intersectionRatio == 0) { return; } else { 「「3//⬇︎alert処理をコメントアウト //alert("出たよ〜"); //画像にclass属性を追加」」 「「1gazou.classList.add("alpha");」」 } }

呼び出される関数の内容を書き換えます。alert処理をコメントアウトして無効にし、画像にclass属性「alpha」を追加します。

こちら⬇︎が完成品です。アニメーション実行は1回のみなので、ゆっくりスクロールしてみてください。

画像が100%表示されたところで、アニメーションが発火しています。
おつかれさまでした!





 

全コードはこちら。


<!DOCTYPE html> <html lang = "ja"> <head> </head> <body>
「「1」」 </body> </html>

こちらが全コードと成増。うまくいきましたか?
手っ取り早く試してみたい方は、コピペすればそのまま再現できます。<img>の所にお好きな画像を仕込んでくださいね。

今回はアニメーションを発火させるだけの目的でしたので、InterSectionObserverの詳しいパラメータなどの解説は省略し、なるべくシンプルなコードに抑えました。コードは短くできたものの、記事自体がすごく長くなってすみません。

そしてもっと複雑なことをしたいケースも出てくるでしょう。例えばアニメーションの対象を1つではなく、すべての<h2>要素に仕込みたいとか・・
そのへんについてもまた、紹介していこうと「思って」います(笑)ではまた〜 ♬











関連記事











「ふ」です。

swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。