スムーススクロールをCSSだけで実装【ずれる分の位置調整も】
スムーススクロールをCSSだけで実装する方法を解説します。
また、よくある「スクロールがずれる問題」の解決方法も併せてご紹介します。
CSSだけでスムーススクロールを実装する方法
scroll-behavior: smooth;
を使う
スムーススクロールをCSSで実装するには、scroll-behavior: smooth;
を<html>
に適用します。
html {
scroll-behavior: smooth;
}
scroll-behavior
はスムーススクロールをたった1行で実装できる、非常に便利なプロパティです。
ブラウザ対応も、2022年9月現在、IEや古いバージョンをカバーしない前提であれば基本的に大丈夫です。
仮にサポート外の環境から閲覧された場合も、レイアウトを組むプロパティなどと違い致命的な問題が発生するわけではないので、その意味でもリスクは少ない手法だと思います。
なお、本記事はCSSでの実装を主旨としていますが、IEや古いバージョンもカバーできるjQueryのコードも後述します。
スクロールがずれるときの位置調整
CSSでの実装に限りませんが、スムーススクロールでスクロールの位置がずれてしまうことはよく見受けられる問題です。
これには固定ヘッダーの裏に隠れるパターンと遅延読み込みによりずれるパターンの2つがありますので、以下でそれぞれの解決方法を解説します。
固定ヘッダーの裏に隠れるパターン
ヘッダーをposition: fixed
で画面上部に固定している場合、スクロール先がヘッダーの裏に隠れてしまうことが考えられます。
これを解説するには下記の2つの手法があります。
- scroll-padding-topを使う
- ネガティブマージンを使う
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
を使う方がよいでしょう。
ネガティブマージンを使う
スムーススクロールのずれを解消するために昔からよく使われている手法です。
padding-top
を指定することでスクロール位置を調整し、その上でmargin-top
にpadding-top
をマイナスにした値を入れて視覚的な余白を相殺します。
h2 /* スクロール先をセレクタに */ {
margin-top: -100px;
padding-top: 100px;
}
ただ、 この場合はスクロールのターゲットになる要素をセレクタとして指定しなければなりません。scroll-padding-top
は<html>
にだけ適用すれば大丈夫なので、これと比べると手間がかかります。
また、スクロールのターゲットになる要素に目に見える余白を指定したい場合はスクロールの位置調整のためのmargin
とpadding
を直接つけられないため、<span>
などを追記する必要が生じます。
遅延読み込みによりずれるパターン
loading="lazy"
などで画像を遅延読み込みさせている場合、スクロール先がずれる可能性があります。
これを回避するには、<img>
にwidth
属性とheight
属性を指定します。そうすることで、画像が読み込まれる前から表示領域が確保され、ずれを防ぐことができます。
<img src="..." alt="..." width="画像の幅" height="画像の高さ">
(番外編)jQueryでスムーススクロールを実装する
CSS のscroll-behavior
はたった1行でスムーススクロールを実装できる便利なプロパティですが、IEや主要ブラウザの古いバージョンにまで対応したい場合は使えません。これらの閲覧環境をカバーしたいときは、 JavaScriptを使う方法が考えられます。
以下に、GMOインターネットグループ様のブログから jQueryのコードを引用させていただきます。上述したスクロールのずれも、固定ヘッダーパターンと遅延読み込みパターンの両方がケアされています。
var $body = $('body,html'); $('a[href^="#"]').on('click', function(e){ var $header = $('.header'); var buffer = 0; if ($header.length){ buffer += $header.innerHeight(); } var speed = 400; var href = $(this).attr("href"); var target = $(href == "#" || href == "" ? 'html' : href); var position = Math.floor(target.offset().top - buffer); smoothScroll(target, position, speed, buffer, 0); return false; }); function smoothScroll(target, position, speed, buffer, count){ count++; if (count > 9 ) return false; $body.animate({ scrollTop: position }, speed, 'swing', function(){ var dest = Math.floor(target.offset().top - buffer); if(dest == position){ return true; } else { scrollsmooth(target, dest, 0, buffer, count); } }); }