今回はJavaScriptを使って、スクロールをしたら対象の要素がふわっとしたから表示されるコードを紹介します。
Web制作などでかなり使えます。
先に仕様をお伝えしておくと、一度表示し終わったら表示したまま残ります。
たまに見かけるような、画面外にいくと一回消えて何回も表示しちゃうような仕様ではないです。
早速コードで見てみよう(コピペOK)
こちらが完成品のコードです。
See the Pen Untitled by WEB-DEN (@Yukiwebcreate) on CodePen.
今回は対象の要素の10%が画面内に入ったら表示されるという仕様になっています。
コードはコピペして、適宜idやクラス名を変更すればすぐ使えると思います。
解説が読みたい方は以降も読んでください!
コードの解説
HTMLはこんな感じです。
<div class="container top">
<p>このエリアは無視してスクロールしてください</p>
</div>
<div class="container">
<div class="target">画面内に入ったらふわっと表示させたい要素</div>
<div class="target">画面内に入ったらふわっと表示させたい要素</div>
<div class="target">画面内に入ったらふわっと表示させたい要素</div>
</div>
今回は.targetが画面内に入ったときにふわっと表示させたい要素ですね。
CSSは下記のような感じ
.container {
margin: 50px;
}
.top {
background-color: lightblue;
height: 800px;
}
.target {
opacity: 0;
transform: translateY(50px);
transition: opacity 1s, transform 1s;
margin: 20px 0;
padding: 20px;
background-color: #f0f0f0;
border: 1px solid #ccc;
min-height: 200px;
}
.target.visible {
opacity: 1;
transform: translateY(0);
}
.targetは初期設定では50px下にズレて、opacityは0になっています。
画面内に入ったら、.visibleクラスがついて元の位置に戻りながら表示されるといった具合です。
さてそれでは肝心のJavaScriptのコードですが、下記のような感じです。
document.addEventListener("DOMContentLoaded", function () {
const targets = document.querySelectorAll(".target");
const observerOptions = {
root: null,
rootMargin: "0px",
threshold: 0.1
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
observer.unobserve(entry.target);
}
});
}, observerOptions);
targets.forEach((target) => {
observer.observe(target);
});
});
こちらは丁寧に解説していきます。
最重要ポイントを解説!IntersectionObserverとは?
今回重要になってくるのは「IntersectionObserver」です。
IntersectionObserverとは、ウェブページ上の要素がビューポート(表示領域)内に入ったり出たりするのを非同期に監視し、その変化を検知してコールバック関数を実行してくれる便利なAPIです。
と言われても難しいと思うので、IntersectionObserverは、
対象の要素が画面内に入ったかどうかを非同期で監視して関数実行してくれるやつ、と覚えていいでしょう。
もっと砕けた言い方をすれば、画面内の変更検知システムみたいなイメージですね。
各処理の解説
さて、それでは早速コード内の各処理で何をやっているのかを解説していきましょう。
まずこのプログラム全体はDOM読み込み完了後に発火するので、
document.addEventListener('DOMContentLoaded', function() {
を記述しています。
そして、画面内に入ったかどうかを判別したい対象の要素を
const targets = document.querySelectorAll('.target');
として定義しています。(複数要素に対応しています)
さて次の行からが重要です。
下記ではIntersectionObserverの設定オプションを定義しています。
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
この設定オプションに従って監視システムであるIntersectionObserverは動作します。
root
観測するルート要素を指定します。null
に設定するとビューポートがルートになります。
rootMargin
ビューポートのマージンを指定します。これにより、観測する領域を広げたり縮めたりできます。
threshold
要素がどの程度ビューポートに入ったときにコールバックを実行するかを指定します。0.1
は要素の10%がビューポートに入ったときにコールバックが呼ばれることを意味します。
そして、IntersectionObserverを使って、観測する要素が変化したときに実行される関数を定義します。
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, observerOptions);
new IntersectionObserver((entries, observer)
としている中のentriesには観測対象の全ての情報が含まれていて、
observerはIntersectionObserverインスタンスそのものを指します。
そのentriesに対して、forEachで各要素にループ処理を実行します。どのような処理かというと、
まずはif文を使ってビューポート内、つまり画面内に要素があるかどうか判別します。
そしてビューポートに入っている場合は観測対象要素である.targetに.visibleクラスを追加し、要素を表示されます。
最後に、observer.unobserve(entry.target);
で、観測している要素が一度ビューポートに入ったら、
これ以上観測しないようにunobserve(アンオブザーブ、つまり観測をやめる)をしています。
解説としては以上です。
横並びの要素にも対応しています
今回のコードは対象の要素が縦に並んでいても、横にならんでいても正しく動作します。
同じクラス名をつけるだけで同じ挙動をさせることができるのでめちゃ便利ですよ。
ただし、横並びにして左から順番に時間差で表示したい、という場合には追加のコードが必要になると思いますので
そうした遅延実装などをしたい場合は任意で行ってください。
参考になれば幸いです!
勉強になります