みなさんこんにちは。
position: sticky;
とoverflow系のプロパティを組み合わせて使ったとき往々にして発生する要素が意図した位置に張り付かなくなってしまう挙動は、いささか分かりづらい点があるためこれに頭を抱えたことがある人は多いことでしょう。
そのため今回の記事では先の挙動がなぜ起こってしまうのか、その理由を記していこうと思います。
結論
position: sticky;
を付与している要素が開発者の意図しているscroll containerに属していないため、先の挙動が発生していると考えられます。
この時点で理解された方はこの先の文章は蛇足と感じるかもしれません。逆に疑問符が頭上に浮かんだ方はこの先で記すposition: sticky;
とscroll containerの関係性を知ることで知見が広がるはずなので是非読み進めてみてください。
閑話休題、それでは詳しい説明に移りましょう。
scroll containerとは
まずはじめに先述したscroll containerとはなにかという話ですが、これはCSS Overflow Moduleの文脈で頻出する概念であり、ざっくりいうとスクロール可能な要素のことを指します。
たとえば、overflow-x
, overflow-y
, overflow
のいずれかのプロパティが設定されていて且つ、それらの値がhidden
, scroll
, auto
である要素はscroll containerです。hidden
が設定されている要素がスクロール可能なのかと疑問を抱く方もいると思いますが、あれはJavaScript経由でスクロールを制御できることからscroll containerに含まれています。
ちなみに、scroll containerの可視範囲のことを「scrollport」と呼びますのでこれも併せて覚えておきましょう。(以下はscroll containerとscrollportの範囲を表した図です)
※scroll containerの下部がうっすらと見えていますがこれは便宜上の表現であり、通常は不可視な領域です。
position: sticky;
とscroll containerの関係性
さて、scroll containerについてはなんとなく理解が進んだところで本命のposition: sticky;
とscroll containerの関係性に迫っていきましょう。
といっても実は単純で、position: sticky;
が付与された要素は直近の祖先であるscroll containerのscrollportを基準にして張り付く仕様となっているため、この2つは非常に密結合な関係にあるのです。付言すればposition: sticky;
を動かしたければ、その祖先にscroll containerを正しく設置しなければいけないということです。
ここらへんを理解せずにoverflow系のプロパティを使っていると、scroll containerが乱立して冒頭で記した通りposition: sticky;
を付与した要素が意図しないscroll containerに属して動かなくなってしまうわけですね。
viewportは暗黙的なscroll container
先の関係性の話を受けて「overflow系のプロパティを指定していなくても(明示的にscroll containerを設置していないくても)position: sticky;
を付与した要素が動くのはなぜなのか」という新たな疑問を持った人がいると思いますが、その疑問は以下に記したUAが準拠している仕様を見ることで氷解できると思います。
- root要素に設定されたoverflowプロパティをviewportに適用しなければならない
- root要素がbodyを子要素にもつhtml要素であって且つ、そのhtml要素のoverflowプロパティの値が
visible
であれば、その子要素であるbody要素のoverflowプロパティの値を適用しなければならない - viewportに使用されるoverflowプロパティの
visible
はauto
と解釈されなければならない
つまり、htmlおよびbody要素のoverflow系プロパティの値をいじらなければviewportが暗黙的にscroll containerとなるので、明示的にoverflow系のプロパティを設定していなくてもposition: sticky;
を付与した要素が動くわけですね。
おわりに
ここまで内容を見ていただいた結果、「position: sticky;をoverflow系のプロパティと組み合わせて使うと期待通りに動かなくなってしまう理由」がわかったのではないでしょうか。
position: sticky;
には今回記したこと以外にも、inset properties(topやleftプロパティなどの総称)が設定されていないと動かないなどの細かい仕様がありますが、それらについてはあまり深く理解していなくてもなんとかなります。逆にscroll containerとの関係性は非常に肝要であり覚えておかないとろくにposition: sticky;
が扱えないのでしっかりと理解を深めておきましょう!
以下、参照記事一覧