スムーススクロールをCSSだけで実装【ずれる分の位置調整も】

著者:牧野健人

スムーススクロールをCSSだけで実装する方法を解説します。

また、よくある「スクロールがずれる問題」の解決方法も併せてご紹介します。

牧野健人

記事の著者牧野健人

株式会社リラクス 代表取締役。CRO・SEOを専門とし、デザイン・実装のスキルも活かしながら、クライアントの成果向上のための取組に尽力。
慶應義塾大学卒業後、行政機関を経て、デジタルマーケティングエージェンシーのアイレップにて運用型広告のクリエイティブプランニングに従事。2019年にリラクスを創業。

お問い合わせはフォームよりお願いいたします。

CSSだけでスムーススクロールを実装する方法

scroll-behavior: smooth; を使う

スムーススクロールをCSSで実装するには、scroll-behavior: smooth;<html>に適用します。

html {
    scroll-behavior: smooth;
}

scroll-behaviorはスムーススクロールをたった1行で実装できる、非常に便利なプロパティです。

ブラウザ対応も、2023年8月現在、IEや古いバージョンをカバーしない前提であれば大丈夫です。

scroll-behaviorのブラウザ対応状況
出典:Can I use

仮にサポート外の環境から閲覧された場合も、レイアウトを組むプロパティなどと違い致命的な問題が発生するわけではないので、その意味でもリスクは少ない手法だと思います。

なお、本記事はCSSでの実装を主旨としていますが、IEや古いバージョンもカバーできるjQueryのコードも後述します。

スクロールがずれるときの位置調整

CSSでの実装に限りませんが、スムーススクロールでスクロールの位置がずれてしまうことはよく見受けられる問題です。

これには固定ヘッダーの裏に隠れるパターン遅延読み込みによりずれるパターンの2つがありますので、以下でそれぞれの解決方法を解説します。

ヘッダーをposition: fixedで画面上部に固定している場合、スクロール先がヘッダーの裏に隠れてしまうことが考えられます。

これを解説するには下記の2つの手法があります。

scroll-padding-topを使う

scroll-padding-topを使うことで、スクロールのターゲットになっている要素が画面の最上部にピッタリつく位置ではなく、指定した分の距離を上に空けた位置に移動するように設定できます。

html {
    scroll-padding-top: 100px;
}

例えばヘッダーの高さが60pxの場合、上記のようにscroll-padding-top: 100px;をかけていれば、ヘッダーの下40pxの位置にスクロールで移動するようになります。

scroll-behaviorと同じくIEや古いバージョンでは対応していないですが、scroll-behaviorを使っている時点でそれらの環境は考慮しない前提なので、使うのに手間がかかる可能性があるネガティブマージンよりもscroll-padding-topを使う方がよいでしょう。

scroll-padding-topのブラウザ対応状況
出典:Can I use
ネガティブマージンを使う

スムーススクロールのずれを解消するために昔からよく使われている手法です。

padding-topを指定することでスクロール位置を調整し、その上でmargin-toppadding-topをマイナスにした値を入れて視覚的な余白を相殺します。

h2 /* スクロール先をセレクタに */ {
    margin-top: -100px;
    padding-top: 100px;
}

ただ、 この場合はスクロールのターゲットになる要素をセレクタとして指定しなければなりません。scroll-padding-top<html>にだけ適用すれば大丈夫なので、これと比べると手間がかかります。

また、スクロールのターゲットになる要素に目に見える余白を指定したい場合はスクロールの位置調整のためのmarginpaddingを直接つけられないため、<span>などを追記する必要が生じます。

遅延読み込みによりずれるパターン

loading="lazy"などで画像を遅延読み込みさせている場合、スクロール先がずれる可能性があります。

これを回避するには、<img>width属性とheight属性を指定します。そうすることで、画像が読み込まれる前から表示領域が確保され、ずれを防ぐことができます。

<img src="..." alt="..." width="画像の幅" height="画像の高さ">

(番外編)JavaScriptでスムーススクロールを実装する

CSS のscroll-behaviorはたった1行でスムーススクロールを実装できる便利なプロパティですが、古いブラウザでは使えない可能性もあります。

これらの環境をカバーしたいときは、 下記のようにJavaScriptを使う方法が考えられます。

document.addEventListener('DOMContentLoaded', () => {
  // ヘッダーエレメントを取得。
  const headerElement = document.querySelector('.header');
  // バッファ(オフセット)の値を設定。スムーズスクロールの際にこの値だけ位置をずらす。
  const buffer = 60;
  // href属性の値が"#"から始まるすべての<a>要素を取得
  document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    // 各<a>要素にクリックイベントのリスナーを追加
    anchor.addEventListener('click', (event) => {
      // デフォルトのクリック動作をキャンセル
      event.preventDefault();
      // ヘッダーの高さを取得。ヘッダーエレメントがない場合は0とする。
      const headerHeight = headerElement ? headerElement.offsetHeight : 0;
      // スクロール時の総オフセットを計算(ヘッダーの高さ + バッファ)
      const totalOffset = headerHeight + buffer;
      // クリックされた<a>要素のhref属性の値を取得
      const targetId = anchor.getAttribute('href');
      // ターゲットとなるエレメントを取得
      const targetElement = document.querySelector(targetId);
      // IDが指定されていない、またはターゲットのエレメントが存在しない場合
      if (targetId === "#" || targetId === "" || !targetElement) {
        alert('適切なスクロール先がありません');
        return; // 以降の処理をスキップ
      }
      // smoothScroll関数を呼び出してスムーズスクロールを実行
      smoothScroll(targetElement, totalOffset);
    });
  });
  // スムーズスクロールを行う関数
  const smoothScroll = (target, offset) => {
    // スクロール先の位置を計算
    const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset;
    // 計算された位置にスムーズにスクロール
    window.scroll({
      top: targetPosition,
      behavior: 'smooth'
    });
  }
});

お気軽にご相談ください

Webサイトに関する課題をお持ちの方はお気軽にご連絡ください。
課題が曖昧な状態でのご相談でも大丈夫です。

サイト改善のプロが無料で分析無料のWebサイト診断 無料相談・見積もり依頼
サイト改善のプロが無料で分析無料のWebサイト診断