読み込み中...

JavaScriptでスクロールしたら表示させる10の手法

JavaScriptでスクロールを制御する方法 JS
この記事は約34分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptでスクロールイベントを使う基本

Webサイトを閲覧していると、スクロールに合わせてヘッダーが固定されたり、要素がフェードインしたりと、動きのあるページを目にすることがありますよね。

こうした動きを実現するには、JavaScriptのスクロールイベントを活用することが重要です。

○スクロールイベントの発火タイミング

スクロールイベントは、ユーザーがページをスクロールするたびに発火します。

つまり、スクロールが止まるまでは常にイベントが発生し続けるということです。

スクロール量が変化するたびに何らかの処理を実行したい場合に便利ですが、イベントの発火頻度が高すぎると、パフォーマンスに影響を与える可能性もあるので注意が必要ですね。

○スクロール量の取得方法

スクロールイベントが発火したタイミングで、現在のスクロール量を知るにはどうすればいいのでしょうか。

実は、window.pageYOffsetプロパティを使えば、簡単に取得することができます。

このプロパティは、ページの上端からのスクロール量をピクセル単位で返してくれるのです。

○サンプルコード1:スクロール量を表示

それでは、実際にスクロール量を取得して表示するサンプルコードを見てみましょう。

window.addEventListener('scroll', function() {
  const scrollAmount = window.pageYOffset;
  console.log(scrollAmount);
});

このコードでは、windowオブジェクトのscrollイベントにイベントリスナーを登録しています。

スクロールが発生するたびに、無名関数が呼び出され、window.pageYOffsetプロパティでスクロール量を取得し、console.logで表示しています。

コンソールを開いた状態でページをスクロールすると、リアルタイムでスクロール量が出力されるはずです。

●特定の要素までスクロールしたら処理を実行

Webサイトを作成していると、「特定の要素が画面内に入ったら、アニメーションを開始したい」とか、「ある要素までスクロールしたら、別の要素を表示したい」といったニーズが出てくることがあります。

こうした要件を実現するには、要素の位置を監視して、スクロール位置と比較する必要があります。

○IntersectionObserverを使った実装

この課題を解決する強力な味方が、IntersectionObserverというAPIです。

IntersectionObserverは、ある要素が画面内に入ったかどうかを監視してくれる機能を持っています。

コールバック関数を登録しておけば、要素が画面内に入ったタイミングで自動的に呼び出されるので、煩雑な処理を書かずに済むのが魅力ですね。

IntersectionObserverを使ったコードは、次のようになります。

const target = document.querySelector('#target');
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('要素が画面内に入りました');
      // 画面内に入ったときの処理をここに書く
    } else {
      console.log('要素が画面外に出ました');
      // 画面外に出たときの処理をここに書く
    }
  });
});
observer.observe(target);

ここでは、監視対象の要素を#targetとしています。

IntersectionObserverのコンストラクタに渡しているコールバック関数内で、isIntersectingプロパティを確認することで、要素が画面内に入ったかどうかを判定しています。

画面内に入ったときと出たときで異なる処理を実行できるので、柔軟に対応できます。

実際にIntersectionObserverを使ってみると、思っていたよりも簡単に実装できるのに驚くかもしれません。

しかし、IntersectionObserverはIE11では対応していないので、注意が必要です。

IE11をサポートしなければいけない場合は、ポリフィルを使うか、別の方法を検討しましょう。

○getBoundingClientRectを使った実装

IntersectionObserverが使えない環境では、getBoundingClientRectメソッドを使って要素の位置を取得し、スクロール位置と比較する方法があります。

getBoundingClientRectは、要素の位置やサイズを含むオブジェクトを返してくれるメソッドです。

ここでは、getBoundingClientRectを使って特定の要素までスクロールしたかどうかを判定するコードを見てみましょう。

const target = document.querySelector('#target');
window.addEventListener('scroll', function() {
  const targetRect = target.getBoundingClientRect();
  if (targetRect.top <= window.innerHeight) {
    console.log('特定の要素までスクロールしました');
    // スクロールしたときの処理をここに書く
  }
});

getBoundingClientRectメソッドで取得した要素の位置情報のうち、topプロパティに注目しています。

これは、要素の上端から画面の上端までの距離を表しています。

一方、window.innerHeightは画面の高さを表します。

したがって、targetRect.top <= window.innerHeightという条件は、「要素の上端が画面の下端より上に来た」というタイミングを表しています。

つまり、要素が画面内に入ったということですね。

この方法は、IntersectionObserverと比べると少し複雑で、パフォーマンスの面でも劣ります。

しかし、IE11でも動作するので、幅広い環境で使えるのがメリットです。

○サンプルコード2:特定要素までスクロールでクラス付与

それでは、特定の要素までスクロールしたら、その要素にクラスを付与するサンプルコードを見てみましょう。

ここでは、IntersectionObserverを使った実装にしています。

<div id="target">ターゲット要素</div>

<style>
.active {
  background-color: yellow;
}
</style>

<script>
const target = document.querySelector('#target');
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      target.classList.add('active');
    } else {
      target.classList.remove('active');
    }
  });
});
observer.observe(target);
</script>

#target要素が画面内に入ったら、activeクラスを付与しています。

これにより、CSSで背景色を黄色に設定しているので、要素が画面内に入るとハイライト表示されるようになります。

画面外に出ると、activeクラスが外れて、元の表示に戻ります。

このように、IntersectionObserverを使えば、監視対象の要素が画面内に入ったかどうかに応じて、柔軟にクラスの付与や削除ができます。

アニメーションを適用したい場合も、クラスを切り替えるだけなので、シンプルに実装できるのが嬉しいポイントですね。

○サンプルコード3:特定要素までスクロールで要素を非表示

続いて、特定の要素までスクロールしたら、別の要素を非表示にするサンプルコードを紹介します。

<div id="target">ターゲット要素</div>
<div id="hidden">非表示にする要素</div>

<style>
#hidden {
  transition: opacity 0.3s;
}
.hidden {
  opacity: 0;
  pointer-events: none;
}
</style>

<script>
const target = document.querySelector('#target');
const hidden = document.querySelector('#hidden');
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      hidden.classList.add('hidden');
    } else {
      hidden.classList.remove('hidden');
    }
  });
});
observer.observe(target);
</script>

ここでは、#target要素が画面内に入ったら、#hidden要素を非表示にしています。

非表示にする際は、opacityプロパティを使って透明度を0にしつつ、pointer-eventsプロパティで要素へのマウスイベントを無効化しています。

これにより、要素が非表示になるだけでなく、クリックもできなくなります。

また、transitionプロパティを使って、opacityの変化にアニメーションを付けています。

これにより、要素がゆっくりとフェードアウトしていくような効果が得られます。

実際に実装してみると、画面内に入ったら特定の要素をスムーズに消していく演出が、とてもシンプルなコードで実現できるのに感動しますよ。

IntersectionObserverの使い方を覚えておくと、こうしたスクロールに連動した処理が手軽に実装できるので、ぜひマスターしておきたいテクニックです。

●スクロール位置の取得と指定

JavaScriptでスクロール操作を行うとき、現在のスクロール位置を知ることや、任意の位置にスクロールさせることは非常によくあるニーズです。

例えば、「トップに戻る」ボタンを実装するときは、現在のスクロール位置に応じてボタンの表示/非表示を切り替えたり、ボタンをクリックしたら一番上までスクロールさせたりといった処理が必要になります。

○scrollTopを使ったスクロール位置の取得

現在のスクロール位置を取得するには、scrollTopプロパティを使います。

これは、要素の上端から、その要素の表示領域の上端までの距離を表します。

windowオブジェクトのscrollTopプロパティを参照すれば、ページ全体のスクロール位置を取得できます。

const scrollTop = window.scrollTop || document.documentElement.scrollTop;
console.log(scrollTop);

ここでは、window.scrollTopdocument.documentElement.scrollTopの両方を確認しています。

これは、ブラウザによってscrollTopプロパティの実装が異なるためです。

モダンなブラウザではwindow.scrollTopで取得できますが、古いIEではdocument.documentElement.scrollTopを使う必要があります。

scrollTopの値は、スクロールが一番上のときは0で、下にスクロールするほど大きくなります。

例えば、100pxスクロールした位置ではscrollTopは100になります。

○scrollToを使ったスクロール位置の指定

一方、任意の位置にスクロールさせるには、scrollToメソッドを使います。

これは、指定した座標までスクロールさせるメソッドで、windowオブジェクトに対して使います。

window.scrollTo(0, 500);

この例では、横方向のスクロール位置を0、縦方向のスクロール位置を500に指定しています。

つまり、ページの一番上から500px下にスクロールさせるという意味です。

scrollToメソッドには、オプションでスクロールの動作を指定することもできます。

window.scrollTo({
  top: 500,
  behavior: 'smooth'
});

このように、behaviorプロパティに'smooth'を指定すると、スムーズにスクロールするようになります。

一気にスクロールするのではなく、ゆっくりとアニメーションしながら目的の位置まで移動するので、ユーザー体験の向上につながります。

○サンプルコード4:ボタンクリックで指定位置にスクロール

それでは、「トップに戻る」ボタンの実装例を見てみましょう。

<button id="scroll-to-top">トップに戻る</button>

<script>
const scrollToTopBtn = document.querySelector('#scroll-to-top');
scrollToTopBtn.addEventListener('click', function() {
  window.scrollTo({
    top: 0,
    behavior: 'smooth'
  });
});
</script>

ここでは、id="scroll-to-top"<button>要素を用意し、それをクリックしたときの処理をaddEventListenerで登録しています。

window.scrollToメソッドを呼び出して、topを0に、behavior'smooth'に指定することで、一番上までスムーズにスクロールさせています。

実際に動かしてみると、「トップに戻る」ボタンをクリックすると、画面が上に向かってゆっくりとスクロールしていく様子が確認できるはずです。

こうした機能は、ページ内の移動を快適にするのに役立ちます。

●ページ最下部・最上部の判定

Webサイトを作成していると、「ページの最下部まで達したら、新しいコンテンツを追加読み込みしたい」とか、「最上部に戻ったら、ナビゲーションメニューのデザインを変更したい」といったニーズが出てくることがあります。

こうした要件を実現するには、ページの最下部や最上部に達したかどうかを判定する必要があります。

○scrollHeightとclientHeightを使った最下部判定

ページの最下部に達したかどうかを判定するには、scrollHeightclientHeightという2つのプロパティを使います。

scrollHeightは、スクロールされる要素の全体の高さを表し、clientHeightは、表示領域の高さを表します。

つまり、scrollHeight - clientHeightは、スクロールされる要素のうち、表示領域に収まらない部分の高さを表します。

これと現在のスクロール位置であるscrollTopを比較することで、最下部に達したかどうかを判定できます。

const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
const scrollTop = window.scrollTop || document.documentElement.scrollTop;

if (scrollTop + clientHeight >= scrollHeight) {
  console.log('ページの最下部に到達しました');
}

ここでは、document.documentElementscrollHeightclientHeightを取得し、window.scrollTopまたはdocument.documentElement.scrollTopでスクロール位置を取得しています。

そして、scrollTop + clientHeightscrollHeight以上であれば、最下部に達したと判定しています。

この判定方法は、ページ全体がスクロールの対象になっている場合に有効です。

特定の要素内でスクロールしている場合は、その要素のscrollHeightclientHeightを使うように注意しましょう。

○scrollTopを使った最上部判定

一方、ページの最上部に達したかどうかを判定するのは、もっと簡単です。

scrollTopが0であれば、最上部にいるということになります。

const scrollTop = window.scrollTop || document.documentElement.scrollTop;

if (scrollTop === 0) {
  console.log('ページの最上部に到達しました');
}

ここでも、window.scrollTopdocument.documentElement.scrollTopの両方を確認して、スクロール位置を取得しています。

scrollTopが0であれば、最上部に達したと判定できます。

最上部の判定は、ページ全体がスクロールの対象でも、特定の要素内でスクロールしている場合でも、同じ方法で行えます。

要素内でスクロールしている場合は、その要素のscrollTopを確認すればいいですね。

○サンプルコード5:最下部判定でローディング表示

それでは、ページの最下部に達したら、新しいコンテンツを追加読み込みする実装例を見てみましょう。

<div id="content">
  <!-- コンテンツ -->
</div>
<div id="loading" style="display: none;">Loading...</div>

<script>
window.addEventListener('scroll', function() {
  const scrollHeight = document.documentElement.scrollHeight;
  const clientHeight = document.documentElement.clientHeight;
  const scrollTop = window.scrollTop || document.documentElement.scrollTop;

  if (scrollTop + clientHeight >= scrollHeight) {
    const loading = document.querySelector('#loading');
    loading.style.display = 'block';

    // 新しいコンテンツを取得する処理をここに書く
    // 取得が完了したら、loading.style.display = 'none'; とする
  }
});
</script>

ここでは、#content要素にコンテンツを表示し、#loading要素でローディング中の表示を行っています。

#loading要素は、初期状態ではdisplay: none;で非表示にしておきます。

windowscrollイベントを監視し、最下部に達したかどうかを判定しています。

最下部に達したら、#loading要素のdisplayスタイルを'block'に変更して、ローディング中の表示を行います。

そして、新しいコンテンツを取得する処理を行います。

この部分は、APIを呼び出したりAjaxで通信したりと、状況に応じて実装が異なるので、ここでは詳細を省略しています。

新しいコンテンツの取得が完了したら、再び#loading要素を非表示にしましょう。

こうすることで、ユーザーがページの最下部までスクロールしたときに、自動的に新しいコンテンツが追加されるようになります。

SNSの投稿一覧などで見かける、無限スクロール機能の基本的な仕組みです。

実際に実装してみると、最下部の判定はそれほど難しくないことがわかると思います。

ページの最上部や最下部に達したタイミングで何らかの処理を行いたい場合は、ぜひこの判定方法を活用してみてください。

●スムーススクロールの実装

Webサイトを閲覧していると、ページ内リンクをクリックしたときに、目的の位置までスムーズにスクロールするサイトを見かけることがあります。

こうしたスムーススクロールの動きがあると、ページ内の移動がスムーズで快適に感じられ、ユーザー体験の向上につながります。

○CSS scroll-behaviorプロパティ

実は、スムーススクロールを実装するのに、JavaScriptを使わなくても済む方法があります。

それが、CSS の scroll-behavior プロパティです。

このプロパティを使えば、シンプルにスムーススクロールを実現できます。

html {
  scroll-behavior: smooth;
}

このように、html 要素に scroll-behavior: smooth; を指定するだけで、ページ内リンクをクリックしたときのスクロールがスムーズになります。

scroll-behavior プロパティには、auto(デフォルト)と smooth の2つの値があり、smooth を指定することでスムーススクロールが有効になるのです。

ただし、scroll-behavior プロパティはまだ比較的新しい機能で、すべてのブラウザで対応しているわけではありません。

特に、IE11では使えないので注意が必要です。

幅広いブラウザ対応が必要な場合は、次に紹介するJavaScriptを使った方法を検討しましょう。

○JavaScriptでスムーススクロールを実装

JavaScriptを使ってスムーススクロールを実装するには、scrollTo メソッドを使います。

先ほど紹介した scroll-behavior プロパティは、ページ内リンクをクリックしたときのスクロールにしか効果がありませんが、JavaScriptを使えば、任意のタイミングでスムーススクロールを発動させることができます。

スムーススクロールを実装するJavaScriptのコードは、次のようになります。

function scrollToSmooth(pos) {
  window.scrollTo({
    top: pos,
    behavior: 'smooth'
  });
}

ここでは、scrollToSmooth という関数を定義しています。

この関数は、スクロール先の位置を引数 pos で受け取り、window.scrollTo メソッドを呼び出してスクロールを実行します。

scrollTo メソッドのオプションで、behavior: 'smooth' を指定することで、スムーススクロールが有効になります。

あとは、この scrollToSmooth 関数を任意のタイミングで呼び出せば、スムーススクロールが実行されます。

例えば、ボタンのクリックイベントに合わせて呼び出すことで、ボタンクリックでスムーススクロールを発動させることができますね。

○サンプルコード6:ページ内リンクのスムーススクロール

それでは、ページ内リンクをクリックしたときにスムーススクロールを実行するサンプルコードを見てみましょう。

<a href="#section1">セクション1へ</a>
<a href="#section2">セクション2へ</a>

<div id="section1">セクション1の内容</div>
<div id="section2">セクション2の内容</div>

<script>
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
  anchor.addEventListener('click', function (e) {
    e.preventDefault();

    const target = document.querySelector(this.getAttribute('href'));
    const targetPosition = target.getBoundingClientRect().top + window.pageYOffset;

    window.scrollTo({
      top: targetPosition,
      behavior: 'smooth'
    });
  });
});
</script>

ここでは、a 要素の href 属性が # で始まるものを選択し、それぞれにクリックイベントを登録しています。

クリックされたら、デフォルトの動作をキャンセルし、href 属性で指定された要素の位置を取得します。

そして、その位置までスムーススクロールするように、window.scrollTo メソッドを呼び出しています。

このコードを使えば、ページ内リンクをクリックしたときに、目的の位置までスムーズにスクロールするようになります。

scroll-behavior プロパティが使えない環境でも、JavaScriptでスムーススクロールを実現できるので便利ですね。

○サンプルコード7:慣性スクロールの実装

スムーススクロールをさらに快適にするテクニックとして、慣性スクロールがあります。

慣性スクロールとは、スクロールを止めたあとも、しばらくの間はスクロールが続くような効果のことです。

まるで、物理的な慣性で動き続けているかのように見えるため、このように呼ばれています。

慣性スクロールを実装するには、少し複雑なコードが必要になります。

function scrollToSmooth(pos) {
  const startPos = window.pageYOffset;
  const distance = pos - startPos;
  const duration = 500;
  let start = null;

  function step(timestamp) {
    if (!start) start = timestamp;
    const progress = timestamp - start;
    const ease = easeInOutCubic(progress, startPos, distance, duration);
    window.scrollTo(0, ease);
    if (progress < duration) window.requestAnimationFrame(step);
  }

  window.requestAnimationFrame(step);
}

function easeInOutCubic(t, b, c, d) {
  t /= d / 2;
  if (t < 1) return c / 2 * t * t * t + b;
  t -= 2;
  return c / 2 * (t * t * t + 2) + b;
}

ここでは、scrollToSmooth 関数の中で、requestAnimationFrame を使ってアニメーションを実装しています。

easeInOutCubic という関数は、イージング関数の一種で、スクロールの速度に変化を付けるために使っています。

慣性スクロールを使うと、スクロールの終了がより自然な感じになります。

通常のスムーススクロールだと、目的の位置に到達した瞬間に止まってしまいますが、慣性スクロールだと、少しオーバーシュートしてから徐々に止まるような動きになります。

ただし、慣性スクロールの実装は少し複雑で、イージング関数の扱いにも慣れが必要です。

また、パフォーマンスへの影響も考慮しなければいけません。

必ずしも慣性スクロールが必要というわけではないので、状況に応じて使い分けましょう。

スムーススクロールの実装方法については以上です。

CSS だけで簡単に実装する方法と、JavaScript を使ってより柔軟に実装する方法を紹介しました。

スムーススクロールを取り入れることで、Webサイトのユーザー体験を向上させることができます。

ぜひ、自分のサイトに取り入れてみてください。

●よくあるエラーと対処法

JavaScriptでスクロール関連の機能を実装していると、思うように動かなくてハマってしまうことがありますよね。

特に、初心者の頃は、エラーが出ても原因がわからず、試行錯誤を繰り返した経験があるのではないでしょうか。

ここでは、スクロール関連の実装でよく遭遇するエラーを取り上げ、その原因と対処法を解説します。

これらのエラーに悩まされている方は多いと思うので、ぜひ参考にしてみてください。

○scrollイベントが発火しない場合の対処法

まず、scrollイベントが発火しない場合の対処法です。

scrollイベントを使って、スクロール時の処理を実装しようとしたのに、全然動かない…というのは、よくある悩みです。

scrollイベントが発火しない原因は、大きく分けて2つあります。

1つ目は、scrollイベントを設定する要素が間違っているケースです。

scrollイベントは、スクロール可能な要素に対して設定する必要があります。

よくあるミスが、documentbody要素にscrollイベントを設定しようとすることです。

この要素はスクロールできないので、scrollイベントは発火しません。

正しくは、windowオブジェクトか、スクロール可能な要素(overflowプロパティがautoscrollに設定されている要素)に対して、scrollイベントを設定します。

// window オブジェクトに対して設定する場合
window.addEventListener('scroll', function() {
  console.log('スクロールされました');
});

// スクロール可能な要素に対して設定する場合
const scrollableElement = document.querySelector('.scrollable');
scrollableElement.addEventListener('scroll', function() {
  console.log('スクロールされました');
});

2つ目は、scrollイベントを設定するタイミングが遅すぎるケースです。

よくあるのが、scrollイベントを設定するコードを</body>タグの直前に書くことです。

この場合、コードが実行されるタイミングでは、すでにスクロールが発生している可能性があります。

これを防ぐには、scrollイベントを設定するコードを<head>タグ内か、<body>タグの直後に書きます。

あるいは、DOMContentLoadedイベントを使って、DOM構築が完了したタイミングでscrollイベントを設定するのも良いでしょう。

document.addEventListener('DOMContentLoaded', function() {
  window.addEventListener('scroll', function() {
    console.log('スクロールされました');
  });
});

これらの点に気をつけることで、scrollイベントが発火しない問題を解決できます。

○スムーススクロールが効かない場合の対処法

続いて、スムーススクロールが効かない場合の対処法です。

せっかくJavaScriptでスムーススクロールを実装したのに、全然スムーズにスクロールしてくれない…という経験をしたことがある方も多いのではないでしょうか。

スムーススクロールが効かない原因は、主に2つあります。

1つ目は、スムーススクロールを実装するコードが間違っているケースです。

特に、scrollToメソッドのオプションであるbehavior: 'smooth'を指定し忘れることが多いです。

behavior: 'smooth'を指定しないと、通常のスクロールになってしまいます。

// 間違った例
window.scrollTo(0, 500);

// 正しい例
window.scrollTo({
  top: 500,
  behavior: 'smooth'
});

2つ目は、ブラウザがスムーススクロールに対応していないケースです。

scrollToメソッドのbehavior: 'smooth'オプションは、比較的新しい機能で、すべてのブラウザで対応しているわけではありません。

特に、IE11では使えません。

これを防ぐには、scroll-behaviorプロパティを使ったCSSでのスムーススクロール実装を検討するか、JavaScriptでスムーススクロールを実装する際に、ブラウザ対応を確認するようにします。

if ('scrollBehavior' in document.documentElement.style) {
  // スムーススクロールに対応しているブラウザ用の処理
  window.scrollTo({
    top: 500,
    behavior: 'smooth'
  });
} else {
  // スムーススクロールに対応していないブラウザ用の処理
  window.scrollTo(0, 500);
}

こうすることで、ブラウザ対応の問題によるスムーススクロールの動作不良を回避できます。

○横スクロールバーが表示されない場合の対処法

最後に、横スクロールバーが表示されない場合の対処法です。

要素の横幅が画面からはみ出しているのに、横スクロールバーが表示されず、はみ出した部分が見えない…というのは、レイアウトを調整する際によく遭遇する問題ですね。

横スクロールバーが表示されない原因は、要素や親要素のoverflow-xプロパティがvisible(デフォルト値)になっているためです。

overflow-xプロパティは、要素の横幅がはみ出した場合の処理を指定するプロパティで、visibleの場合は、はみ出した部分が見えなくなります。

これを防ぐには、はみ出す可能性のある要素やその親要素にoverflow-x: auto;を指定します。

overflow-x: auto;を指定すると、要素の横幅がはみ出した場合に、自動的に横スクロールバーが表示されるようになります。

.horizontal-scroll {
  overflow-x: auto;
}

また、はみ出す可能性のある要素にwidthプロパティを指定して、明示的に横幅を設定するのも良いでしょう。

.horizontal-scroll {
  overflow-x: auto;
  width: 100%;
}

このように、overflow-xプロパティとwidthプロパティを適切に設定することで、横スクロールバーが表示されない問題を解決できます。

●スクロール関連の応用例

これまで、スクロールイベントの基本的な使い方や、スクロール位置の取得・指定、スムーススクロールの実装方法などを解説してきました。

上述した知識を組み合わせるだけで、Webサイトのユーザー体験を向上させる様々な機能を実装することができます。

ここでは、スクロール関連のテクニックを応用した実装例を3つ紹介します。

実際のWebサイトでよく見かける機能ばかりなので、ぜひ参考にしてみてくださいね。

○サンプルコード8:スクロールでヘッダーを固定・解除

1つ目は、スクロールに合わせてヘッダーを固定・解除する機能です。

Webサイトを閲覧していると、ページの上部にあるヘッダーが、スクロールすると画面上部に固定されるようになるサイトを見かけますよね。

これは、ユーザーがページ内を移動しやすくするための工夫の1つです。

この機能は、スクロール位置を監視して、一定量スクロールしたらヘッダーにposition: fixed;を指定することで実装できます。

<header id="header">ヘッダー</header>

<script>
const header = document.querySelector('#header');
const headerHeight = header.offsetHeight;

window.addEventListener('scroll', function() {
  if (window.pageYOffset >= headerHeight) {
    header.style.position = 'fixed';
    header.style.top = '0';
  } else {
    header.style.position = '';
    header.style.top = '';
  }
});
</script>

ここでは、ヘッダー要素の高さ(headerHeight)を取得しておき、スクロール位置(window.pageYOffset)がヘッダーの高さ以上になったら、ヘッダーにposition: fixed;top: 0;を指定して、画面上部に固定しています。

スクロール位置がヘッダーの高さ未満になったら、positiontopのスタイルを解除して、元の位置に戻すようにしています。

このように、スクロール位置を監視することで、スクロールに合わせてヘッダーの表示を切り替えることができます。

ヘッダーメニューが常に表示されていると、ページ内の移動がスムーズになるので、ユーザビリティの向上につながりますね。

○サンプルコード9:スクロール連動のパララックス効果

2つ目は、スクロールに連動したパララックス効果の実装です。

パララックス効果とは、背景とコンテンツで異なるスクロール速度を設定することで、奥行きのある表現を演出する手法です。

Webサイトのデザインにアクセントを付けるのに効果的ですよ。

パララックス効果は、スクロール位置に応じて背景の位置をずらすことで実装できます。

具体的には、background-positionプロパティを使って、背景画像の位置を調整します。

<div id="parallax"></div>

<style>
#parallax {
  height: 400px;
  background-image: url('path/to/image.jpg');
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
}
</style>

<script>
const parallax = document.querySelector('#parallax');

window.addEventListener('scroll', function() {
  const scrollPosition = window.pageYOffset;
  parallax.style.backgroundPositionY = scrollPosition * 0.5 + 'px';
});
</script>

ここでは、#parallax要素に背景画像を指定し、background-attachment: fixed;で背景画像を固定しています。

そして、スクロール位置(window.pageYOffset)に応じて、background-positionプロパティのY座標を調整しています。

scrollPosition * 0.5としているのがポイントで、スクロール位置の半分の速度で背景画像を移動させることで、パララックス効果を演出しています。

0.5の値を変更することで、パララックス効果の強弱を調整できます。

このように、スクロール位置に応じて背景画像の位置をずらすことで、奥行きのある表現を実現できます。

Webサイトのデザインに動きを加えることで、ユーザーの印象に残りやすくなりますよ。

○サンプルコード10:無限スクロールの実装

3つ目は、無限スクロールの実装です。

無限スクロールとは、ページの最下部までスクロールすると、自動的に次のコンテンツを読み込んで表示する機能のことです。

SNSのタイムラインなどでよく見かける機能ですね。

無限スクロールは、ページの最下部までスクロールしたかどうかを判定し、最下部に達したらAjaxで次のコンテンツを取得して表示することで実装できます。

<div id="content">
  <!-- コンテンツ -->
</div>

<script>
const content = document.querySelector('#content');

window.addEventListener('scroll', function() {
  const scrollPosition = window.innerHeight + window.pageYOffset;
  const threshold = document.documentElement.offsetHeight - 100;

  if (scrollPosition >= threshold) {
    // 次のコンテンツを取得して表示する処理をここに書く
  }
});
</script>

ここでは、windowscrollイベントを監視し、スクロール位置(window.innerHeight + window.pageYOffset)がしきい値(document.documentElement.offsetHeight - 100)以上になったら、次のコンテンツを取得して表示するようにしています。

しきい値は、ドキュメントの高さから任意の値(ここでは100px)を引いた値にしています。

これは、コンテンツの最下部に到達する少し手前でコンテンツを読み込み始めるようにするためです。

次のコンテンツを取得して表示する処理は、APIを呼び出してデータを取得し、取得したデータをもとにコンテンツを生成して#content要素に追加する、といった流れになります。

具体的な実装は、APIの仕様やデータの構造によって異なるので、ここでは割愛します。

無限スクロールを実装することで、ユーザーは次々とコンテンツを閲覧できるようになり、ページ内の回遊率を高めることができます。

ただし、大量のコンテンツを一度に読み込むと、パフォーマンスが低下する可能性があるので、適切な量のコンテンツを読み込むようにしましょう。

まとめ

本記事では、JavaScriptを使ってスクロールに関連する様々な機能を実装する方法を紹介してきました。

スクロールイベントの基本的な使い方から、特定の要素までスクロールしたときの処理、スクロール位置の取得と指定、ページの最下部・最上部の判定、スムーススクロールの実装など、スクロールに関するテクニックを幅広く取り上げました。

また、実装する際によくつまずくポイントとその対処法も解説し、より実践的な知識が身につくように心がけました。

さらに、ヘッダーの固定・解除やパララックス効果、無限スクロールなど、スクロール関連のテクニックを応用した実装例も紹介しました。

本記事で紹介した内容を理解することで、スクロールを活用したより魅力的なWebサイトを制作できるようになるでしょう。

スクロールは、ユーザーとWebサイトのインタラクションを豊かにする重要な要素です。

ユーザーがページをスクロールしたときに、どのような体験を提供できるかを考えながら、スクロールを活用したWebサイト作りを楽しんでいただければと思います。