ガイド: スクロールまわりを CSS だけで作る(スナップ・停止位置・現在地表示・カルーセルのタブ)
スクロール UI は「どこで止めるか」「どこまで手前で止めるか」「いまどこを見ているか」の3つに分けて考えると整理しやすい。どれも以前は JS(スライダーライブラリ、scrollTo のオフセット計算、Intersection Observer)で書いていたが、いまは CSS で置き換えられる。
1. どこで止めるか — scroll-snap
- 親に
scroll-snap-type、子にscroll-snap-alignの2点セット。1枚ずつ止めたいならscroll-snap-stop: always。 - 詳しくは scroll-snap で JS なしの「カード単位で止まる」横スクロールスライダー
2. どこまで手前で止めるか — scroll-padding / scroll-margin
- スクロールコンテナ側の
scroll-padding-*と、止まる要素側のscroll-margin-*で停止位置をずらす。固定ヘッダーの裏に見出しが潜る問題もスナップの余白もこれで調整する。 - 詳しくは 固定ヘッダーにページ内リンクの見出しが隠れるのを scroll-padding-top で一括で防ぐ
3. いまどこを見ているか — スクロールマーカーと :target-current
同じ「スクロールマーカー」の仕組みを2通りに使える(Chromium 系のみ、2026-10 時点)。
| 用途 | マーカーになるもの | 指定 |
|---|---|---|
| 記事の目次ハイライト | 既存の <a href="#…"> | 親に scroll-target-group: auto |
| カルーセルのタブ・ドット | 各スライドの ::scroll-marker 疑似要素 | スクロール領域に scroll-marker-group: before など |
| カルーセルの前へ・次へボタン | ― | スクロール領域に ::scroll-button(left) / ::scroll-button(right) |
どちらも表示中の項目に :target-current が当たるので、ハイライトの書き方は共通。
- 目次 :target-current で目次の「いま読んでいる項目」をCSSだけでハイライト
- カルーセル ::scroll-marker と scroll-marker-group で、スクロールスナップのカルーセルに JS なしのタブを付ける
- 前へ・次へボタン ::scroll-button() でカルーセルの前へ・次へボタンを JS なしで付ける
4. スクロール量に動きを連動させる — animation-timeline
- 読了バーや表示時のフェードは
animation-timeline: scroll()/view()で JS なしに書ける。2026-10 に Firefox 159 が対応し、全主要ブラウザで使えるようになった。詳しくは スクロール駆動アニメーション(animation-timeline: scroll() / view())が全主要ブラウザで使えるようになった。
組み合わせ例
タブ付きカルーセル = 1(スナップ)+ 2(scroll-padding-inline で端の余白)+ 3(::scroll-marker のタブ)。3 に未対応のブラウザでも 1 と 2 だけで普通の横スクロールスライダーとして動くので、段階的に足していける。
関連
- スクロールの「溢れ」を検知してレイアウトを切り替える応用 ナビが溢れたら CSS だけでドロワーに切り替える(scroll-timeline で溢れ検知)
- 横スクロール領域の作り方の注意 横スクロールするテーブルはラッパーで包む(table に overflow-x は効かない)
- 横スクロールの表で見出し行をページ上端に固定する overflow: auto clip で横スクロールの表でも見出し行をページ上端に固定する(単一軸スクロールコンテナー)