最終更新日:
display:flexなのにposition:stickyが効かない問題
こんにちは。五平餅くんです。
今回はposition: stickyにハマったので、そちらについてお話していきます!
position: stickyについては、以下の記事をご覧ください!
position: stickyが効かない…
position: stickyを指定しているのに効かない場合のひとつは、親要素または祖先要素にfloatプロパティが使用されている時です。
つまり、position: stickyは親要素または祖先要素に高さがないと無効になります。
なので横並びレイアウトで子要素にposition: stickyを使いたいときは、flexboxを使えば良いというのはたくさんのブログに書いてありました。
が!しかし!
とあるサイトで同じようにflexboxで横並び、その子要素にposition:stickyで画面固定をしましたところ、見事に撃沈…。
原因がわからず何時間も苦悩し続けましたが、ようやく答えが見つかりました。
今回は、その原因についてお話していきます。
まずは、以下のようにそのサイトの構成を作ってみます。
<div id="content">
<div class="inner">
<div class="main">
<div class="main-content">
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
<h1>ここにメインコンテンツが入ります</h1>
</div>
<div class="sidebar">
<div class="sidebar-inner">
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
</div>
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
</div>
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
</div>
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
<h4>ここがposition: sticky;になります</h4>
</div>
</div>
</div>
</div>
</div>
</div>
.inner {
max-width: 800px;
width: 97%;
margin: 0 auto;
}
.main {
display: flex;
}
.main-content {
width: 70%;
background: #f5f5f5;
}
.sidebar {
width: 25%;
margin-left: auto;
}
.sidebar-content {
margin-bottom: 30px;
background: #888;
color: #fff;
}
.sidebar-content:last-of-type {
position: sticky;
top: 30px;
}
以下から上のコーディングをデモ表示できます
position: stickyを指定した要素(サイドバーの一番下)が画面固定でついてくるはずでしたが、ついてきません。
親要素にflexboxも使っています(display: flexの部分)。また、position: stickyの指定場所も問題ない。
なんでだーーーーーーーーーーーーーーーーーー!!!!!!
結論
犯人が分かりました。
<div class=”main-content”>は無視して、<div class=”sidebar”>から下をご覧ください。
<div class="sidebar">
<!--犯人↓↓-->
<div class="sidebar-inner">
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
</div>
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
</div>
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
</div>
<div class="sidebar-content">
<h4>ここにサイドバーのコンテンツが入ります</h4>
<h4>ここがposition: sticky;になります</h4>
</div>
</div>
こいつです。
<div class=”sidebar-inner”>
当然、<div class=”sidebar”>の高さはあります。画面下まで十分な高さです。
しかしこれが<div class=”sidebar-inner”>が間にいると…
あれ、高さ全然ない…。
つまり、原因はこうです。
position: stickyの特徴として、要素の位置までスクロールした時、親要素の中で位置を固定するという性質があります。
なので、<div class=”sidebar-inner”>がこの高さしかないのであれば、スクロールしていってposition: stickyが画面固定になる頃には<div class=”sidebar-inner”>は十分な高さが残っていないためpositiotn: stickyは画面固定されないのです。
対処法
簡単です。<div class=”sidebar-inner”>にheight: 100%を指定してあげてください。
/*親要素であるsidebar-contentと同じ高さにする*/
.sidebar-inner {
height: 100%;
}
以下から上のコーディングのデモを表示できます。
または、<div class=”sidebar-inner”>をhtmlから削除するという手もあります。
まとめ
今回は、親要素にdisplay: flexを指定しているのに、子要素にposition: stickyが効かない問題について解説させていただきました。
なるべくhtmlはシンプルにし、不要なタグはなるべく削除した方が良いということですね。
最後まで読んでいただきありがとうございました。
補足
height: 100%を指定してもdisplay:stickyが効かない時、下記を確認してみてください。
- display: flexの直下の子要素にdisplay:stickyを指定していないか
→display: flexの直下の子要素は、それ以外の横並びの要素と同じ高さになるのでついてこない場合があります。その場合、display:stickyと一緒に「align-items: baseline」を追加で指定すると解決します。 - 親要素のいずれかにoverflow: hiddenの指定がある
→body、htmlを含むいずれかの親要素にoverflow: hiddenが指定されていると効きません - floatで横並びにした要素の子要素にdisplay:stickyを指定した場合
→display:flexと違い、floatは高さが確保されないため、display:stickyが効きません