【JavaScript】JavaScriptのみを使用してスクロール時に画像をふわっと表示させる方法

はじめに

こんにちは。ナオキです!

今回はJavaScriptのみを使用して画像をふわっと表示させる方法を紹介します。ぜひ参考にしてください!

対象読者

  • JavaScript初学者の方
  • JavaScriptでスクロール処理を行いたい方

スクロール処理に使用するもの

今回はJavaScriptのIntersectionObserverを使用してスクロール処理を実装したいと思います!

IntersectionObserverとはターゲット要素を監視し、その要素が特定の領域内にに入ったり出たりするのを検知し、ターゲット要素と特定の領域が交差している時に関数を実行させることができます!

scrollイベントでも簡単に実装することは出来ますが、スクロールするたびにイベントが発火してしまうのでパフォーマンス的にあまり良く有りません。それに比べてIntersectionObserverは非同期で実行されるのでパフォーマンスにも影響しにくいです。

見本とコード説明

見本

スクロールしたら画像をふわっと表示

Webサイトでよく見るスクロール処理です。
HTML CSS JavaScriptは以下のようになります!

HTML

<body>
  <img id="image" src="image/dog.jpg" alt="dog" />
</body>

CSS

body {
  padding: 100vh 0;
  background-color: #d1e9ed;
}

#image {
  width: 600px;
  margin: 0 auto;
  opacity: 0;
 transition: 4s;
}

JavaScript

// ① ターゲット要素を取得
const image = document.getElementById("image");

// ③ オプション設定 ※デフォルトで良いなら記述しなくでも大丈夫です!
const options = {
  threshold: 0.5,
};

// ④ 要素が表示されたら実行
function showImage(entries) {  
  if (entries[0].isIntersecting) {
    image.style.opacity = 1;
  }
}

// ② IntersectionObserverを呼び出す
const observer = new IntersectionObserver(showImage, options);

// ⑤ 実行
observer.observe(image);

コード説明

HTMLで表示させたい画像を記述します。

CSSでは、bodyでスクロール分の余白を取っています。
imageで、opacity: 0を指定し画像を透明にしておき、transition: 4sを指定しふわっと表示されるようにします。

JavaScriptでは、まず①のイベントを発火させたい要素をdocument.getElementById()にて取得しています。

次に、②でIntersectionObserver()を呼び出します。第1引数に実行したい関数、第2引数にはオプションの設定を書いていきます。

③でオプションを記述しています。オプションプロパティは以下の3つがあります!

  • root
    • 監視するベースとなる要素を指定できます。
    • 初期値はブラウザのviewportになります。
      viewportとは、表示領域のことです。今現在見ているページの範囲がviewportになります!
  • rootMargin
    • 交差を感知するルートからの距離、こちらを利用してイベントを発生させる位置を調整できます。
    • 指定の仕方は、marginプロパティと同じで("10px 20px 30px 0px")のように記述します。
    • 初期値は("0px 0px 0px 0px")になります。
      0pxの場合0しか記述しないとエラーが出てしまうので、0pxと記述するように注意してください!
  • thresholds
    • ターゲット要素が見えてから、どの位置でイベントを発火させるか調整できます。
    • 0 ~ 1や配列を指定できます。0はターゲットが見え初めた瞬間にイベントが発火し、1はターゲットがすべて見えてる状態でイベントが発火します。
    • 初期値は0になります。

オプションは初期値で良ければ何も記述しなくて大丈夫です!

④で要素が表示されたら実行したい関数を記述しています。
関数の第1引数にはIntersectionObserverentryオブジェクトを記述します。entryオブジェクトはIntersectionObserverと一緒に使えるもので、以下のプロパティがあります!

  • boundingClientRect
    • ターゲット要素が画面上にどのように表示されているかの情報を返します。具体的にいうと、その要素が画面上でどの位置にあり、どれだけの幅と高さを持っているかを返します。
  • intersectionRatio
    • ターゲット要素が現在どの程度見えているかを0.0 ~ 1.0の間の値で返します。
  • intersectionRect
    • ターゲット要素が特定の領域に入っている部分の位置やサイズを返します。
  • isIntersecting
    • ターゲット要素が特定の領域に入ったらtrueを返し、入っていなければfalseを返します。
  • rootBounds
    • ターゲット要素がどの領域に対して交差を判定しているかを返します。
  • target
    • ターゲット要素を返します。
  • time
    • ターゲット要素と特定の領域が交差状態になった時刻を返します。

今回はisIntersectingを使用しています!
今回の場合は要素がルートに入ったら透過を無くしたいのでimage.style.opacity = 1と記述しています。

⑤でobserver.observe(ターゲット要素)と記述することでターゲット要素の監視が開始されます!

以上がコードの説明になります!

オプションプロパティ、entryオブジェクトについてもっと詳しく知りたい方はこちらの公式ドキュメントを参照してください!

おまけ

少し工夫をしたら、このようなものも簡単に作れます!

HTML

<div id="box" class="box">
   <p class="text">スクロールしてね!</p>
</div>

CSS

body {
  padding: 100vh 0;
  background-color: #d1e9ed;
}

.box {
  padding: 200px 0;
  margin: 0 auto;
  position: relative;
}

.box::after {
  position: absolute;
  content: "";
  top: 0;
  left: 0;
  background: #5df56f;
  width: 100%;
  height: 100%;
  z-index: -1;
  transform: translateX(-100%);
  animation-name: none;
  animation-duration: 2s;
  animation-fill-mode: forwards;
  transform: translateX(-100%);
}
@keyframes box_slide {
  0% {
    transform: translate(-100%, 0);
  }
  100% {
    transform: translate(0, 0);
  }
}

.text {
  font-size: 3rem;
  align-items: center;
  width: fit-content;
  margin: 0 auto;
}

JavaScript

const box = document.getElementById("box");
const sheets = document.styleSheets;
const sheet = sheets[sheets.length - 1];

const options = {
  threshold: 1,
};

function showBox(entries) {
  if (entries[0].isIntersecting) {
    sheet.insertRule(
      ".box::after { animation-name: box_slide }",
      sheet.cssRules.length
    );
  }
}

const observer = new IntersectionObserver(showBox, options);

observer.observe(box);

さいごに

今回はIntersectionObserverを使って簡単にスクロール処理を実装する方法を紹介しました。

この他にも色々なことができるのでぜひ試してみてください!