本文へスキップ
JavaScript 応用 JavaScript scroll resize

スクロールや画面サイズの変化を扱おう

更新日:2026-08-02

スクロール位置や画面幅に応じた処理は便利ですが、短時間に何度もイベントが発生する点に注意します。

今回は長いページへ「ページ上部へ戻る」ボタンを設置し、表示条件、スムーズスクロール、連続イベントの制御を実装します。

今回使用するファイル構成

javascript-practice/
├── index.html
├── css/
│   └── style.css
└── js/
    └── script.js

ブラウザの画面イベントを扱う

ページ上部へ戻るボタンを作る

<button id="back-to-top" type="button" hidden>ページ上部へ戻る</button>
const backToTop = document.querySelector('#back-to-top');

window.addEventListener('scroll', () => {
  backToTop.hidden = window.scrollY < 500;
});

backToTop.addEventListener('click', () => {
  window.scrollTo({ top: 0, behavior: 'smooth' });
});

scrollYは現在の縦方向のスクロール量です。

画面幅の変化を受け取る

function showViewportWidth() {
  console.log(window.innerWidth);
}

window.addEventListener('resize', showViewportWidth);

見た目の切り替えはCSSのメディアクエリを優先します。JavaScriptは、画面幅に応じて処理そのものを変える必要がある場合に使います。

頻繁な実行を抑える

let resizeTimer;

window.addEventListener('resize', () => {
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(showViewportWidth, 200);
});

連続イベントが落ち着いてから処理する方法をデバウンスと呼びます。

上部へ戻るボタンを完成させる

CSSで位置を固定する

#back-to-top {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  padding: 0.75rem 1rem;
}

#back-to-top[hidden] {
  display: none;
}

position: fixedにより、ページをスクロールしても画面右下に残ります。hidden属性の表示規則を別のCSSで上書きしないようにします。

初期表示にも同じ判定を使う

const backToTop = document.querySelector('#back-to-top');

function updateBackToTop() {
  backToTop.hidden = window.scrollY < 500;
}

window.addEventListener('scroll', updateBackToTop, { passive: true });
updateBackToTop();

関数へ分けると、イベント発生時と初期表示で同じ判定を利用できます。passive: trueは、このリスナーがスクロールをpreventDefault()で止めないとブラウザへ伝えます。

動きの軽減設定を尊重する

backToTop.addEventListener('click', () => {
  const prefersReducedMotion = window.matchMedia(
    '(prefers-reduced-motion: reduce)'
  ).matches;

  window.scrollTo({
    top: 0,
    behavior: prefersReducedMotion ? 'auto' : 'smooth',
  });
});

大きな動きで体調を崩す利用者もいます。OSやブラウザで「視差効果を減らす」が設定されている場合は、即座に移動します。

リサイズ処理を改善する

デバウンスを再利用できる関数にします。

function debounce(callback, delay) {
  let timerId;

  return (...args) => {
    clearTimeout(timerId);
    timerId = setTimeout(() => {
      callback(...args);
    }, delay);
  };
}

const handleResize = debounce(() => {
  console.log(`現在の幅:${window.innerWidth}px`);
}, 200);

window.addEventListener('resize', handleResize);

返された関数は、呼ばれるたびに前回のタイマーを解除します。リサイズが200ミリ秒止まってから最後の一回だけ処理します。

CSSとJavaScriptの役割を分ける

画面幅に応じた列数、余白、文字サイズはメディアクエリで実装します。JavaScriptを使うのは、通信するデータを変えるなど処理上の理由がある場合です。JavaScriptでPC用・スマートフォン用のHTMLを別々に生成すると、リサイズ時の状態管理が複雑になります。

まとめ

スクロールとリサイズは発生回数を意識し、CSSで解決できる見た目の処理と分けます。次の記事ではJavaScriptエラーの調査方法を学びます。