display:flexなのにposition:stickyが効かない問題

  • このエントリーをはてなブックマークに追加
display: flexなのにposiiton: stickyが効かない問題

こんにちは。五平餅くんです。

今回はposition: stickyにハマったので、そちらについてお話していきます!

position: stickyについては、以下の記事をご覧ください!

cssのみでtableの項目を固定(ロック)する

 

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”>の高さ。青い部分。

 

しかしこれが<div class=”sidebar-inner”>が間にいると…

<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はシンプルにし、不要なタグはなるべく削除した方が良いということですね。

最後まで読んでいただきありがとうございました。

  • このエントリーをはてなブックマークに追加

SNSでもご購読できます。