雑記: position: sticky; で固定できなかった話

2022-04-12 認識がおかしかったので修正します。冒頭に絵を追加しました。
f:id:cookie-box:20220412102554p:plain

参考文献

  1. css position stickyが効かない時の解決策!Flex-box使用時に効かなくなる? – CHEATPARK – 神戸三宮のシステム開発会社CHEAT. https://cheat.co.jp/blog/archives/1896(参照日 2022年4月10日).
    • 本記事はこちらの記事と趣旨が同一である。なお、align-self の値は baseline でなくても、サイドバーの高さがメインコンテンツの高さに合わせてストレッチするのを防ぐものであればよい [5]。
  2. FlexBox と position sticky でサイドメニューをスクロール途中で固定. https://syumi3.com/sonota/html_pasokon/flexbox-sticky.html(参照日 2022年4月10日).
    • align-items を指定するのではなく各フレックスアイテムに明示的に高さを指定している例である。
  3. display:flexなのにposition:stickyが効かない問題 | 五平餅くんの部屋. https://goheymochikun.com/position-sticky/(参照日 2022年4月10日).
    • 記事のタイトルからして本記事と同じ状況と思いきやこれは似て非なるパターン同じ状況である。[1] 及び本記事はスティッキーアイテムの縦幅が長すぎるのが要因だが、こちらの記事はスティッキーコンテナの縦幅が短すぎることが要因になっている。
  4. position: sticky;の仕組みや実際の使い方をやさしく解説 | コリス. https://coliss.com/articles/build-websites/operation/css/css-position-sticky-how-it-really-works.html(参照日 2022年4月10日).
    • position: sticky; について丁寧に記述されていたのでこれを読んで修正できた。
  5. https://developer.mozilla.org/ja/docs/Web/CSS/align-items(参照日 2022年4月10日).
    • フレックスコンテナの align-items プロパティのデフォルト値がかかれている。なお、交差軸(cross axis)とは主軸と直交する方向のことであり、デフォルトでは主軸が画面の「左 → 右」方向のはずなので、交差軸は画面の「上 → 下」方向である。
  6. https://developer.mozilla.org/ja/docs/Web/CSS/position(参照日 2022年4月10日).


私はこちらのページのデザインを下図の test1.html のように実装していた(ソースは本記事の最下部にある)(下図で緑色、ピンク色、水色、黄色にしている箇所は実際には透明である)。
f:id:cookie-box:20220410231557p:plain
test1.html はまずページにフレックスコンテナとなる div 要素(緑色)を置き、フレックスコンテナにサイドバー用 div 要素(ピンク色)とメインコンテンツ用 main 要素(水色)をフレックスアイテムとして並べ、それぞれ子要素の div 要素(薄黄色、白色)にテキストを記述している。ポイントとして、サイドバー子要素(薄黄色)を position: sticky; にすることでメインコンテンツをスクロールしてもサイドバーは画面に固定されるようにしている。白色の領域の一部が隠れるまでブラウザの縦幅を狭くしてから下にスクロールすると、薄黄色の領域はブラウザ画面の上に出ていかずその場にとどまることがわかるはずである。

test1.html はよく覚えていないが適当に検索しながらこう実装したものであり、これはこれで意図通りに動作する。しかし、よく考えるとフレックスアイテムにわざわざ子要素をもたせる必要があるのか疑問に思う。といってもメインコンテンツ子要素(白色)はデザイン上必要なのでサイドバー子要素(薄黄色)を撤去してみることにする。このとき position: sticky; はサイドバー要素(ピンク色)に付け替える。そうしてスクロールすると、図の「メインページに戻る」の文字は画面にとどまらず画面の上に出ていってしまう(test2.html)。

それもそのはずで、top: a; position: sticky; が設定された要素が画面にある場合に画面を下にスクロールされたときの挙動は冒頭の絵のようになる(絵の上段では一般例として a > 0 であって初期位置が親要素内の上端ではない例を示している)。そして test2.html は絵の左下の失敗例になってしまっている。ので、ピンク色の要素の長さが水色の要素の長さと揃わないようにすればよい(test3.html)。こちらのページもそう修正した。



test3.html は以下である。
test2.html は test3.html から align-items: flex-start; を削除したものである。
test1.html は test3.html から align-items: flex-start; を削除した上で div.sidebar の内側にもう一つ div 要素を置き div.sidebar ではなく内側の div 要素のほうに top: 0; position: sticky; を指定したものである。

<html>
<head>
<style type="text/css">
<!--
body {
    margin: 0;
    background: lightgray;
}
div.container {  /* フレックスコンテナ */
    width: 500px;
    display: flex;
    align-items: flex-start;  /* 規定値の stretch から変更し高さを揃えないように */
    background: lightgreen;
    border-right: 4px solid lightgreen;  /* デバッグ用 */
    border-bottom: 4px solid lightgreen;  /* デバッグ用 */
}
div.sidebar {  /* フレックスアイテム(サイドバー)*/
    box-sizing: border-box;  /* 指定サイズ内でパディングを取るよう指示 */
    flex-basis: 100px;
    top: 0;
    position: sticky;
    padding: 20px;
    background: mistyrose;
}
main.main {  /* フレックスアイテム(メイン)*/
    flex-basis: 400px;
    background: powderblue;
}
main.main>div.item {
    margin: 15px 0;
    padding: 20px;
    background: white;
}
-->
</style>
</head>
<body>
<div class="container">
    <div class="sidebar">
        メインページに戻る
    </div>
    <main class="main">
        <div class="item">
            ほげほげ<br/>ふがふが<br/>ほげほげ<br/>ふがふが<br/>
            ほげほげ<br/>ふがふが<br/>ほげほげ<br/>ふがふが<br/>
            ほげほげ<br/>ふがふが<br/>ほげほげ<br/>ふがふが<br/>
            ほげほげ<br/>ふがふが<br/>ほげほげ<br/>ふがふが<br/>
        </div>
    </main>
</div>
</body>
</html>