【JavaScript】特定の位置までスクロールさせる方法|scrollTo・scrollIntoView・スムーズスクロール

【JavaScript】特定の位置までスクロールさせる方法|scrollTo・scrollIntoView・スムーズスクロール JavaScript

JavaScriptで特定の位置までスクロールさせたい場面は頻繁にあります。「トップに戻る」ボタン、ページ内リンク、フォームのエラー箇所へのジャンプなど、スクロール制御はWebアプリに欠かせない機能です。

この記事では、window.scrollTo()Element.scrollIntoView()window.scrollBy() の3つのメソッドを中心に、スムーズスクロールの実装方法から実務パターンまで体系的に解説します。

この記事で学べること

  • window.scrollTo() で絶対位置にスクロールする方法
  • Element.scrollIntoView() で要素を画面内に表示する方法
  • window.scrollBy() で相対的にスクロールする方法
  • CSS・JavaScriptによるスムーズスクロールの実装
  • トップに戻るボタン・ページ内リンク・エラー箇所ジャンプなど実務パターン
  • 固定ヘッダーとの重なり対策・ブラウザ互換性の注意点
スポンサーリンク

window.scrollTo() の使い方

window.scrollTo() はページ全体を指定した座標(絶対位置)にスクロールさせるメソッドです。最もシンプルなスクロール制御方法で、ページの特定のY座標にジャンプしたいときに使います。

基本構文(x, y座標指定)

引数に x座標(水平方向)と y座標(垂直方向)をピクセル単位で指定します。

JavaScript
// 基本構文: window.scrollTo(x座標, y座標)

// ページ最上部へスクロール
window.scrollTo(0, 0);

// 垂直方向に500pxの位置へスクロール
window.scrollTo(0, 500);

// 水平・垂直の両方を指定
window.scrollTo(100, 300);

scrollTo() の座標はページ左上を原点(0, 0)とした絶対位置です。現在のスクロール位置に関係なく、常に同じ位置に移動します。

オプション指定(behavior: 'smooth')

オブジェクト形式で引数を渡すと、スクロールの挙動(behavior)を指定できます。behavior: 'smooth' でスムーズスクロールになります。

JavaScript
// オプション形式(推奨)
window.scrollTo({
  top: 500,       // 垂直方向の位置(px)
  left: 0,        // 水平方向の位置(px)
  behavior: 'smooth'  // スムーズスクロール
});

// behavior の値
// 'smooth' : なめらかにスクロール
// 'instant': 即座にジャンプ
// 'auto'   : ブラウザのデフォルト動作

ページ最上部・最下部へのスクロール

よく使うパターンとして、ページの最上部と最下部へのスクロール方法を紹介します。

JavaScript
// ページ最上部へスムーズスクロール
window.scrollTo({
  top: 0,
  behavior: 'smooth'
});

// ページ最下部へスムーズスクロール
window.scrollTo({
  top: document.documentElement.scrollHeight,
  behavior: 'smooth'
});

// 特定要素の位置までスクロール
const element = document.getElementById('target');
const rect = element.getBoundingClientRect();
window.scrollTo({
  top: rect.top + window.scrollY,
  behavior: 'smooth'
});

ポイント:document.documentElement.scrollHeight はページ全体の高さを返します。これを top に指定すると、ページの最下部までスクロールできます。

Element.scrollIntoView() の使い方

Element.scrollIntoView() は、指定した要素が画面内に表示されるようにスクロールするメソッドです。scrollTo() と違い、座標を計算する必要がなく、要素を直接指定できるため実務では最もよく使われます。

基本構文

引数なし、またはboolean値を渡すシンプルな使い方から見ていきましょう。

JavaScript
const target = document.getElementById('section-2');

// 引数なし(デフォルト): 要素の上端がビューポートの上端に来る
target.scrollIntoView();

// true: 要素の上端がビューポートの上端に来る(デフォルトと同じ)
target.scrollIntoView(true);

// false: 要素の下端がビューポートの下端に来る
target.scrollIntoView(false);

オプション(behavior, block, inline)

オブジェクト形式で細かい制御が可能です。behavior(スクロール挙動)、block(垂直方向の配置)、inline(水平方向の配置)の3つのプロパティを指定できます。

JavaScript
target.scrollIntoView({
  behavior: 'smooth',  // 'smooth' | 'instant' | 'auto'
  block:    'start',   // 'start' | 'center' | 'end' | 'nearest'
  inline:   'nearest'  // 'start' | 'center' | 'end' | 'nearest'
});
プロパティ 説明
behavior smooth なめらかにアニメーション
behavior instant 即座にジャンプ
block start 要素の上端をビューポートの上端に合わせる
block center 要素を画面の中央に表示
block end 要素の下端をビューポートの下端に合わせる
block nearest 最も近い端に合わせる(スクロール量最小)
inline nearest 水平方向も最も近い端に合わせる(デフォルト)

固定ヘッダーがある場合のずれ対策(scroll-margin-top)

scrollIntoView() を使うと、固定ヘッダー(position: fixed)の下に要素が隠れてしまうことがあります。これは CSSの scroll-margin-top で簡単に解決できます。

CSS
/* 固定ヘッダーの高さ分だけ余白を確保 */
scroll-margin-top: 80px;

/* スクロールターゲットになりうる全見出しに適用 */
h2, h3, h4 {
  scroll-margin-top: 80px;
}
JavaScript
// CSSで scroll-margin-top を指定済みなら
// scrollIntoView() はその余白を考慮してスクロールする
const heading = document.getElementById('section-title');
heading.scrollIntoView({
  behavior: 'smooth',
  block: 'start'
});

// JavaScript側で手動計算する方法もある
const headerHeight = 80;
const targetPos = heading.getBoundingClientRect().top + window.scrollY - headerHeight;
window.scrollTo({
  top: targetPos,
  behavior: 'smooth'
});

ポイント:scroll-margin-top はCSSだけで完結するため、JavaScriptで座標計算するよりもシンプルです。固定ヘッダーがあるサイトでは、スクロールターゲットに設定しておくことをおすすめします。

window.scrollBy() で相対的にスクロール

window.scrollBy() は、現在のスクロール位置から相対的に移動するメソッドです。scrollTo() が「ページ上のどこへ移動するか(絶対位置)」なのに対し、scrollBy() は「今の位置からどれだけ動かすか(相対位置)」を指定します。

JavaScript
// 基本構文: window.scrollBy(x, y)

// 下に300pxスクロール
window.scrollBy(0, 300);

// 上に200pxスクロール(負の値)
window.scrollBy(0, -200);

// オプション形式(スムーズスクロール)
window.scrollBy({
  top: 500,
  left: 0,
  behavior: 'smooth'
});

// 1画面分スクロール
window.scrollBy({
  top: window.innerHeight,
  behavior: 'smooth'
});
メソッド スクロール方式 使いどころ
scrollTo() 絶対位置 特定の座標に移動したいとき
scrollBy() 相対位置 今の位置から一定量動かしたいとき
scrollIntoView() 要素指定 特定の要素を画面に表示したいとき

スムーズスクロールの実装パターン

スムーズスクロールにはいくつかの実装方法があります。目的に応じて最適な方法を選びましょう。

CSS scroll-behavior: smooth(最もシンプル)

CSSだけでページ全体のスクロール動作をスムーズにできます。JavaScriptを1行も書かずにスムーズスクロールを実現する最もシンプルな方法です。

CSS
/* ページ全体のスクロールをスムーズに */
html {
  scroll-behavior: smooth;
}

/* アクセシビリティ対応: アニメーション無効設定のユーザーには即座にスクロール */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}
HTML
<!-- CSSだけでアンカーリンクがスムーズスクロールになる -->
<a href="#section1">セクション1へ</a>
<a href="#section2">セクション2へ</a>

<h2 id="section1">セクション1</h2>
<h2 id="section2">セクション2</h2>

scroll-behavior: smoothhtml 要素に設定するだけで、ページ内のアンカーリンク(#id)クリック時と、JavaScriptの scrollTo()/scrollIntoView() でのスクロールがすべてスムーズになります。

JavaScriptの behavior: 'smooth'

CSSではなくJavaScriptでスムーズスクロールを制御したい場合は、各スクロールメソッドのオプションに behavior: 'smooth' を指定します。特定の操作だけをスムーズにしたい場合に便利です。

JavaScript
// scrollTo() でスムーズスクロール
window.scrollTo({ top: 0, behavior: 'smooth' });

// scrollIntoView() でスムーズスクロール
element.scrollIntoView({ behavior: 'smooth' });

// scrollBy() でスムーズスクロール
window.scrollBy({ top: 300, behavior: 'smooth' });

アンカーリンクのスムーズスクロール(JavaScript実装)

CSSの scroll-behavior が使えない環境や、より細かい制御が必要な場合は、JavaScriptでアンカーリンクのスムーズスクロールを実装します。

JavaScript
// ページ内アンカーリンクをすべてスムーズスクロールに
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
  anchor.addEventListener('click', function(e) {
    e.preventDefault();

    const targetId = this.getAttribute('href');
    const targetElement = document.querySelector(targetId);

    if (targetElement) {
      targetElement.scrollIntoView({
        behavior: 'smooth',
        block: 'start'
      });
    }
  });
});

注意:e.preventDefault() を忘れると、アンカーリンク本来の動作(一瞬でジャンプ)が先に実行されてしまいます。必ず呼び出しましょう。

実務でよく使うパターン集

ここからは、実際のWebサイト・Webアプリで頻繁に登場するスクロール制御のパターンを紹介します。コピー&ペーストですぐに使えるコードを揃えました。

「トップに戻る」ボタン

一定量スクロールすると表示される「トップに戻る」ボタンは、多くのサイトで実装されています。表示/非表示の切り替えとスムーズスクロールを組み合わせます。

HTML
<button id="back-to-top" aria-label="ページトップに戻る">
  ▲ TOP
</button>
CSS
#back-to-top {
  position: fixed;
  bottom: 20px;
  right: 20px;
  padding: 12px 16px;
  background: #0284c7;
  color: #fff;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s, visibility 0.3s;
  z-index: 1000;
}

#back-to-top.visible {
  opacity: 1;
  visibility: visible;
}
JavaScript
const backToTopBtn = document.getElementById('back-to-top');

// スクロール量に応じてボタンの表示/非表示を切り替え
window.addEventListener('scroll', () => {
  if (window.scrollY > 300) {
    backToTopBtn.classList.add('visible');
  } else {
    backToTopBtn.classList.remove('visible');
  }
});

// クリックでトップへスムーズスクロール
backToTopBtn.addEventListener('click', () => {
  window.scrollTo({
    top: 0,
    behavior: 'smooth'
  });
});

ページ内リンク(目次からのジャンプ)

ブログや技術文書でよくある、目次から各セクションへジャンプするパターンです。固定ヘッダーのオフセットも考慮した実装を紹介します。

JavaScript
// 固定ヘッダーを考慮したページ内リンク
function scrollToSection(sectionId, offset = 80) {
  const target = document.getElementById(sectionId);
  if (!target) return;

  const elementTop = target.getBoundingClientRect().top;
  const scrollPosition = elementTop + window.scrollY - offset;

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

// 目次リンクにイベント設定
document.querySelectorAll('.toc-link').forEach(link => {
  link.addEventListener('click', (e) => {
    e.preventDefault();
    const id = link.getAttribute('href').slice(1);
    scrollToSection(id);
  });
});

フォームバリデーション後にエラー箇所へスクロール

長いフォームでバリデーションエラーが発生した際、最初のエラー箇所を画面に表示するのはUXの基本です。

JavaScript
function validateAndScroll() {
  const errors = validateForm();

  if (errors.length > 0) {
    // エラーメッセージを表示
    showErrors(errors);

    // 最初のエラー要素を取得
    const firstError = document.querySelector('.error');

    if (firstError) {
      // エラー箇所を画面中央に表示
      firstError.scrollIntoView({
        behavior: 'smooth',
        block: 'center'
      });

      // フォーカスも移動(アクセシビリティ)
      firstError.focus({ preventScroll: true });
    }

    return false;
  }

  return true;
}

ポイント:focus({ preventScroll: true }) を使うと、フォーカス移動時の自動スクロールを防ぎ、scrollIntoView() のスムーズスクロールを活かせます。

無限スクロールでの位置保持

無限スクロール(Infinite Scroll)では、コンテンツを追加した後にスクロール位置がずれないよう、位置の保存と復元が重要になります。

JavaScript
class InfiniteScroll {
  constructor(container, loadMore) {
    this.container = container;
    this.loadMore = loadMore;
    this.isLoading = false;
    this.init();
  }

  init() {
    // スクロール監視にIntersection Observerを使用
    const sentinel = document.createElement('div');
    sentinel.id = 'scroll-sentinel';
    this.container.appendChild(sentinel);

    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting && !this.isLoading) {
        this.load();
      }
    });

    observer.observe(sentinel);
  }

  async load() {
    this.isLoading = true;

    // 現在のスクロール位置を保存
    const scrollPos = window.scrollY;

    await this.loadMore();

    // 位置を復元(上方向にコンテンツ追加した場合)
    window.scrollTo(0, scrollPos);

    this.isLoading = false;
  }
}

よくあるミスと注意点

スクロール制御は一見シンプルですが、実装時にハマりやすいポイントがいくつかあります。

scrollIntoView() のブラウザ対応

scrollIntoView() 自体はほぼすべてのブラウザで使えますが、オプション(オブジェクト引数)のサポート状況には注意が必要です。

機能 Chrome Firefox Safari Edge
scrollIntoView(boolean) 1+ 1+ 3+ 12+
scrollIntoView(options) 61+ 36+ 15.4+ 79+
scrollTo(options) 45+ 36+ 15.4+ 79+
scroll-behavior CSS 61+ 36+ 15.4+ 79+

2024年以降、主要ブラウザはすべてオプション引数をサポートしています。古いSafari(15.3以前)を考慮する場合は、polyfillの smoothscroll-polyfill を導入するか、boolean引数にフォールバックしましょう。

固定ヘッダーとの重なり問題

固定ヘッダー(position: fixedposition: sticky)があるサイトでは、スクロール先の要素がヘッダーの下に隠れてしまう問題がよく発生します。

JavaScript
// 方法1: CSS scroll-margin-top(推奨)
// CSSで対象要素に設定するだけ

// 方法2: JavaScript で offsetを計算
function scrollToWithOffset(element, offset = 0) {
  const y = element.getBoundingClientRect().top
    + window.scrollY
    - offset;

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

// 方法3: ヘッダー高さを動的に取得
function scrollToElement(element) {
  const header = document.querySelector('header');
  const headerHeight = header ? header.offsetHeight : 0;

  const y = element.getBoundingClientRect().top
    + window.scrollY
    - headerHeight
    - 16;  // 余白

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

SPA(Single Page Application)でのスクロール位置リセット

React や Vue.js などのSPAでは、ページ遷移時にスクロール位置がリセットされないことがあります。ルーティング時にスクロール位置を管理する必要があります。

JavaScript(React Router v6)
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

// ページ遷移時にトップへスクロールするコンポーネント
function ScrollToTop() {
  const { pathname } = useLocation();

  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return null;
}
JavaScript(Vue Router)
// Vue Router のスクロール動作設定
const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    // ブラウザバック時は位置を復元
    if (savedPosition) {
      return savedPosition;
    }

    // ハッシュがある場合はその要素へ
    if (to.hash) {
      return {
        el: to.hash,
        behavior: 'smooth'
      };
    }

    // それ以外はトップへ
    return { top: 0 };
  }
});

注意:SPAではページ遷移がブラウザのネイティブなページ読み込みではないため、スクロール位置が自動リセットされません。フレームワークのルーター機能でスクロール制御を明示的に設定しましょう。

scroll イベントのパフォーマンス

scrollイベントは高頻度で発火するため、ハンドラ内で重い処理を行うとパフォーマンスに影響します。throttlerequestAnimationFrameで制御しましょう。

JavaScript
// 悪い例: scrollイベントで毎回重い処理
window.addEventListener('scroll', () => {
  // 毎回実行される(1秒間に数十回)
  heavyOperation();
});

// 良い例: requestAnimationFrameで間引く
let ticking = false;

window.addEventListener('scroll', () => {
  if (!ticking) {
    window.requestAnimationFrame(() => {
      handleScroll();
      ticking = false;
    });
    ticking = true;
  }
});

// 良い例: passive オプションでスクロール性能を改善
window.addEventListener('scroll', handleScroll, { passive: true });

ポイント:{ passive: true } を指定すると、ブラウザに「このハンドラは preventDefault() を呼ばない」と伝えるため、スクロールのパフォーマンスが向上します。スクロールを監視するだけの場合は常に指定しましょう。

まとめ

JavaScriptでスクロール位置を制御する方法を、3つのメソッドと実務パターンに分けて解説しました。最後に、各メソッドの特徴を比較表でまとめます。

メソッド スクロール方式 スムーズ対応 主な用途
window.scrollTo() 絶対位置(座標指定) behavior: smooth トップに戻る、特定座標へ移動
Element.scrollIntoView() 要素指定 behavior: smooth 特定要素を画面内に表示
window.scrollBy() 相対位置(差分指定) behavior: smooth 現在位置から一定量移動
scroll-behavior CSS ページ全体 CSS指定 アンカーリンクのスムーズ化

実装の選び方まとめ

  • ページ全体のスムーズスクロール → CSSの scroll-behavior: smooth が最もシンプル
  • 特定の要素を表示したいscrollIntoView() が座標計算不要で便利
  • 固定ヘッダーがある → CSSの scroll-margin-top で余白を確保
  • 座標を細かく制御したいscrollTo() + getBoundingClientRect()
  • SPA → ルーターの設定でスクロール位置をリセット
  • アクセシビリティprefers-reduced-motion を考慮する

スクロール制御はWeb開発で頻出するテクニックです。この記事で紹介した3つのメソッドの違いを理解し、実装シーンに応じて最適な方法を選択してください。特に scrollIntoView()scroll-margin-top の組み合わせは、シンプルかつ確実なので最もおすすめです。