スクロール関連のCSSの便利機能2つ
開発環境
- next.js 15.x(App Router)
- react 19.x
- tailwindcss 4.3.x
前提
UI を作っていると、機能的には問題ないのに「なんか気持ち悪い」と感じるスクロール周りの挙動に出くわします。
特に最近詰まったのが次の2つです。
- ページの内容量によってスクロールバーが出たり消えたりして、レイアウトが左右にガタつく
- モーダルの中をスクロールし切ると、背面のページまで一緒に動いてしまう
どちらも JS で頑張りたくなりがちですが、実は Tailwind のユーティリティ1個で解決できました。
この記事ではその2つを、Next.js + Tailwind v4 構成での書き方とあわせて整理します。
本題
scrollbar-gutter: stable でレイアウトのガタつきを消す
⚠️ 問題:スクロールバーの有無で横幅が変わる
中央寄せのレイアウトを組んでいると、ページA(コンテンツ少なめ・スクロールバーなし)からページB(コンテンツ多め・スクロールバーあり)に遷移したときに、コンテンツが数 px 横にズレることがあります。
原因は、スクロールバーが表示されるとその分だけ表示領域(ビューポート幅)が狭くなるためです。
// スクロールバーが出る/出ないでこの中央寄せがズレる
<main className="mx-auto max-w-3xl">{children}</main>🛠 改善:スクロールバーの領域を常に確保する
scrollbar-gutter: stable を使うと、スクロールバーが出ていないときでもその分の溝(gutter)を確保してくれます。結果、出っぱなしでも引っ込んでいてもレイアウト幅が変わりません。
これは Tailwind v4.3 から専用ユーティリティが追加されたので、arbitrary property を書かずに済みます(v4.2 以前は [scrollbar-gutter:stable] のように書く必要がありました)。
ビューポート全体のスクロールに効かせたいので、html 要素に付けます。
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja" className="scrollbar-gutter-stable">
<body>{children}</body>
</html>
);
}対応するユーティリティは次の3つです。
- scrollbar-gutter-auto:scrollbar-gutter: auto;(デフォルト。必要なときだけ溝を作る)
- scrollbar-gutter-stable:scrollbar-gutter: stable;(常に溝を確保する)
- scrollbar-gutter-both:scrollbar-gutter: stable both-edges;(左右両方に溝を作り、対称を保つ)
👉 ポイント まずは scrollbar-gutter-stable を html に付ける。左右対称にこだわるなら scrollbar-gutter-both。
overscroll-behavior でスクロールの連鎖を止める
⚠️ 問題:モーダル内のスクロールが背面に伝播する
モーダルやドロワー、コメント欄のような「内側にスクロール領域がある UI」でよくあるのがこれです。
内側の要素をスクロールし切ったあと、さらにスクロールすると、その勢いが親(背面のページ)に伝わってページ全体が動いてしまいます。これは scroll chaining と呼ばれる挙動です。
// モーダルの中身。末端まで行くと背面のページが動く
<div className="max-h-80 overflow-y-auto">
{longContent}
</div>🛠 改善:overscroll-contain で連鎖を断つ
overscroll-behavior: contain を指定すると、その要素のスクロールが末端に達しても親へ伝播しなくなります。こちらは以前から Tailwind に専用ユーティリティがあります。
<div className="max-h-80 overflow-y-auto overscroll-contain">
{longContent}
</div>対応するユーティリティは次の3つです。
- overscroll-auto:デフォルト(連鎖する)
- overscroll-contain:連鎖は止めるが、末端での「バウンド」表現は残す
- overscroll-none:連鎖もバウンドも止める
縦方向だけ止めたいなら overscroll-y-contain のように軸を絞ることもできます。
👉 ポイント モーダルやドロワーには overscroll-contain を付けておくと、背面が動く違和感をまとめて潰せます。
どちらも「JSに逃げる前にCSSを見る」
この2つに共通するのは、JS でスクロールイベントを拾って制御したくなる場面を、CSS(Tailwind ユーティリティ)の指定ひとつで済ませられる点です。
- レイアウトのガタつき → scrollbar-gutter-stable
- スクロールの連鎖 → overscroll-contain
実装が減るぶんバグも減るので、まず CSS で解けないか確認する癖がついてきました。
さいごに
どちらも知っていれば一瞬、知らないと JS で消耗する系のプロパティでした。
特に scrollbar-gutter は、デザイナーから「ページ遷移でちょっとガタつく」と言われて初めて原因に気づいたもので、地味だけど体験への効きはかなり大きいと感じています。Tailwind v4.3 で専用ユーティリティになったことで、より気軽に入れられるようになりました。
スクロール周りで「なんか気持ち悪い」と思ったら、まず CSS のスクロール系プロパティを思い出してみてください。