本記事では、私が過去案件で少しハマったoverflow: hidden
の罠について話していこうと思います。
罠1: overflow-x/overflow-yにhiddenを指定した時になんかうまくいかなくなる
See the Pen trap1-default by tsukaD (@gqzoomig-the-lessful) on CodePen.
上の状態から、「overflow content」のp
要素の表示を維持した上で、右側にはみ出た.inner
内のインラインテキストを表示させないようにしたかったとします。
See the Pen trap1-hidden by tsukaD (@gqzoomig-the-lessful) on CodePen.
overflow-x: hidden
でいけるやん!……と思って追加したら、横に溢れた文字の非表示はうまく行ったものの、なぜか縦方向にスクロールされるように……😱
解決策
overflow-x: clip
を使いましょう
See the Pen trap1-clip by tsukaD (@gqzoomig-the-lessful) on CodePen.
罠2: stickyした時になんかうまくいかなくなる
See the Pen Untitled by tsukaD (@gqzoomig-the-lessful) on CodePen.
overflow: hidden
を指定した親要素.inner
内の.header
要素にposition: sticky
を指定していますが、うまく固定されていません……。
解決策
overflow: clip
を使いましょう
See the Pen trap2-clip by tsukaD (@gqzoomig-the-lessful) on CodePen.
overflow:hiddenの罠の正体
雑に「clipを使いましょう」で片付けてしまいましたが、一体なぜ、clip
ではうまくいくのに、hidden
だとうまくいかないのでしょう?
それは、overflow: hidden
にすると、スクロールコンテナが生成されるからです。
前提として、overflow
プロパティには
-
visible
(初期値) hidden
clip
scroll
auto
の5種類の値があります。
そのうち、スクロールコンテナを生成するのは、scroll
、auto
、そして hidden
です。
scroll
とauto
は、挙動からしてそりゃそうだろうという感じですが、hidden
がスクロールコンテナを生成するというのはなかなかイメージしにくいのではないでしょうか。
……ただ実は、MDNの説明を読むと、hidden
にした時点でスクロールコンテナを生成するのではなく、アンカーやJSによるスクロールが行われた時点でスクロールコンテナを生成するようです。
が、別にこの条件が満たされていなくても、スクロールコンテナを生成していないと説明がつかないような挙動をhidden
はします(特に後述のstickyとの関係など)。スクロールコンテナが生成されている状態とは別に、スクロールコンテナスタンバイみたいな状態がCSS上にあるということなのでしょうか。
この辺は調べてもよくわからなかったので、本記事では便宜上hidden
はスクロールコンテナを生成するものとして扱います。
罠1の正体
これについては、仕様としてはっきりと記載されていました。
overflow-y が hidden、scroll、auto のいずれかで、 overflow-x プロパティが visible (既定値)の場合、この値は暗黙的に auto として計算されます。
つまり、罠1では、overflow-x
にのみhidden
を指定してしまっていたから、初期値のままにしていたもう片方のoverflow-y
にauto
が適用され、縦方向のスクロールバーが勝手に発生してしまっていたというわけです。
なんでこんな仕様にしているかということなのですが、おそらく片方のoverflowのhiddenでスクロールコンテナを生成した時点で、もう片方に非スクロールのvisibleを当てはめることができなくなり、かといって明示的にxにのみhiddenを設定しているのに、勝手にもう片方にもhiddenが当たるのもよくないので、折衷案としてautoにしたのではないかと勝手に想像しています。
(ちなみに、overflow-x: hidden; overflow-y:clip
とすると、overflow-y
が自動的にhidden
に変更されます。これもスクロールコンテナの兼ね合いだと思われます)
罠2の正体
これは、position: sticky
側の仕様を見ると答えが書いてあります。
この値は、常に新しい重ね合わせコンテキストを生成します。なお粘着要素は、直近の祖先がスクロールしない場合でも、「スクロールの仕組み」を持つ直近の祖先(overflow が hidden, scroll, auto, overlay として作成されたもの)に「粘着」します。
つまり罠2では、overflow: hidden
によって.inner
要素に対してスクロールコンテナが生成されたため、sticky
要素の位置の基準が、本来のビューポートから、「「スクロールの仕組み」を持つ直近の祖先」である.inner要素に更新されるということが起こってしまったわけです。
overflow: clip
にすると、スクロールコンテナは生成されませんから、stickyの基準位置も元通りビューポートになります。
まとめ
何かと癖の強いoverflow: hidden
ですが、「スクロールコンテナを生成する」ということを頭に入れておけば、少しだけ仲良くなれるのではないでしょうか。
改めて、こういった仕様を理解しておくことは大事だなあと感じます。