モーダルダイアログのスクロールロックでレイアウトがガタつく問題
- #CSS
- #Web標準
- #dialog要素
- #Tips
最近でもないけれど、スクロールロック時に画面幅がガタガタするのをよく見るような気がする、というメモ書き。
body.clientWidth の違いでがんばっていたあの頃
スクロールロックを書いてる時、ロック前のスクロールバーの幅を取得して、ロック後にその値だけbody要素とかにpadding-right当てたくなる。昔は画面幅とか拾って頑張っていました。
なんの話かわからないMacユーザさんは、いったん外観設定から「スクロールバーを表示」の設定で「常に表示」に変更しておきましょう。
スクロールバーがでるくらいのコンテンツ量を持つページでhtml要素にoverflow: hidden;をつけると、コンテンツ幅がガタつきますよね。
そんなお悩みはCSS1行追加で解決
:root {
scrollbar-gutter: stable;
}scrollbar-gutterはスクロールバーが表示される領域(ガター)をあらかじめ確保したい時に便利なプロパティです。
値 | 振る舞い |
|---|---|
| 通常通りスクロールバーが必要になったらコンテンツ幅が狭まる。 |
| スクロールバーの有無にかかわらず、スクロールバーが表示される領域を確保しておく。 |
| スクロールバーの領域を確保しつつ、反対側にも同じ幅だけ余白を生み出す(コンテンツが左右中央に配置される)。 |
筆者はスクロールバーは「常に表示」にしていますが、その場合はスクロールバーが不要な状態でもスクロールバーの領域が確保されます。
なにもせずにガタガタさせておくよりは、とりあえずstableにするのが良さそうです👀
ついでにつけたいoverscroll-behavior
モーダルダイアログを開いている時、モーダル内のコンテンツをスクロールして最後まで到達すると、背景のbody要素がスクロールしてしまう問題があります。これをscroll chainingと呼びます。
dialog {
overscroll-behavior: contain;
}overscroll-behaviorは、指定するだけでscroll chainingを防ぐことができる優れものです!
値 | 振る舞い |
|---|---|
| スクロールが親要素に伝播する(デフォルト) |
| スクロールが親要素に伝播しない。 |
| スクロールが親要素に伝播しない。macOSやiOSで見られるスクロール端でのバウンドなどの独自動作も無効化される[1]。 |
🍣 実装例
究極、たった3つのルールセットを書くだけでいままで苦労してきたスクロール周りの制御まですっかり綺麗に対応されます[2]。
:root {
scrollbar-gutter: stable;
}
:root:has(dialog:modal) {
overflow: hidden;
}
dialog {
overscroll-behavior: contain;
}前回の記事でも紹介していたdialog[closedby]もそうですが、いつの間にかダイアログUIまわりの進化がすごいですね。
これ以外にも、いつの間にかできるようになっていることがたくさんあるので、引き続きCSSの進化にも注目していきたいです💃🍣
参考文献
scrollbar-gutter: CSS Overflow Module Level 3
overscroll-behavior:CSS Overscroll Behavior Module Level 1