My position: sticky element isn't sticky when using flexbox

CssFlexboxCss PositionSticky

Css Problem Overview


I was stuck on this for a little bit and thought I'd share this position: sticky + flexbox gotcha:

My sticky div was working fine until I switched my view to a flex box container, and suddenly the div wasn't sticky when it was wrapped in a flexbox parent.

.flexbox-wrapper {
  display: flex;
  height: 600px;
}
.regular {
  background-color: blue;
}
.sticky {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  background-color: red;
}

<div class="flexbox-wrapper">
  <div class="regular">
    This is the regular box
  </div>
  <div class="sticky">
    This is the sticky box
  </div>
</div>

JSFiddle showing the problem

Css Solutions


Solution 1 - Css

Since flex box elements default to stretch, all the elements are the same height, which can't be scrolled against.

Adding align-self: flex-start to the sticky element set the height to auto, which allowed scrolling, and fixed it.

Currently this is supported in all major browsers, but Safari is still behind a -webkit- prefix, and other browsers except for Firefox have some issues with position: sticky tables.

.flexbox-wrapper {
  display: flex;
  overflow: auto;
  height: 200px;          /* Not necessary -- for example only */
}
.regular {
  background-color: blue; /* Not necessary -- for example only */
  height: 600px;          /* Not necessary -- for example only */
}
.sticky {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  top: 0;
  align-self: flex-start; /* <-- this is the fix */
  background-color: red;  /* Not necessary -- for example only */
}

<div class="flexbox-wrapper">
  <div class="regular">
    This is the regular box
  </div>
  <div class="sticky">
    This is the sticky box
  </div>
</div>

JSFiddle showing the solution

Solution 2 - Css

In my case, one of the parent containers had overflow-x: hidden; applied to it, which will break position: sticky functionality. You'll need to remove that rule.

No parent element should have the above CSS rule applied to it. This condition applies to all parents up to (but not including) the 'body' element.

Solution 3 - Css

If you are using flex in the parent element use align-self: flex-start for the element which you want to make sticky.

position: sticky;
align-self: flex-start;
top: 0;
overflow-y: auto;

Solution 4 - Css

You can also try adding a child div to the flex item with the contents inside and assign position: sticky; top: 0; to that.

That worked for me for a two column layout where the contents of the first column needed to be sticky and the second column appear scrollable.

Solution 5 - Css

For my situation, the align-self: flex-start (or justify-self: flex-start) solution does not work. I need to keep overflow-x: hidden as well since some containers swipe horizontally.

My solution required nested display: flex with overflow-y: auto to get the desired behaviors:

  • header can adjust height dynamically, which prevents playing with position: absolute or position: fixed
  • content scrolls vertically, constrained horizontally to the view width
  • sticky element can be anywhere vertically, sticking to the bottom of the header
  • other elements can slide horizontally
    • looks like the SO snippet tool can't render width on child elements to properly to demonstrate the horizontal slide, or maybe there's some other setting on my actual layout that makes it work...
    • note that a wrapper element that does nothing else is required to allow overflow-x: auto to work correctly in elements under a parent with overflow-x: hidden

body {
  height: 100vh;
  width: 100vw;
  display: flex;
  flex-direction: column;
}

body>header {
  background-color: red;
  color: white;
  padding: 1em;
}

.content {
  overflow-x: hidden;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

article {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.horizontal_slide {
  display: flex;
  overflow-x: auto;
  background-color: lightblue;
  padding: .5em;
}

.horizontal_slide>* {
  width: 1000px;
}

.toolbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background-color: lightgray;
  padding: .5em;
  display: flex;
}

<header>Fancy header with height adjusting to variable content</header>
<div class="content">
  <article class="card">
    <h1>One of several cards that flips visibility</h1>
    <div class="overflow_x_wrapper">
      <div class="horizontal_slide">
        <div>Reason why `overflow-x: hidden` on the parent is required
        </div>
        <div>Reason why `overflow-x: hidden` on the parent is required
        </div>
        <div>Reason why `overflow-x: hidden` on the parent is required
        </div>
      </div>
      <div class="toolbar">Sticky toolbar part-way down the content</div>
      <p>Rest of vertically scrollable container with variable number of child containers and other elements</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
        dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  </article>
  </div>

Solution 6 - Css

I made a makeshift flexbox table and had this problem. To solve it, I simply put the sticky header row outside of the flexbox, just before it.

Solution 7 - Css

Global solution/rule from my experience:

Do not put structures with sticky elements directly inside { display : flex } containers.

Instead (for flex layouts) put your tables/divs with sticky elements inside a flex sub-container (e.g. with { flex: 1 1 auto }, but without { display : flex } ), then everything should work as intended.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbholtbholtView Question on Stackoverflow
Solution 1 - CssbholtbholtView Answer on Stackoverflow
Solution 2 - CssTheoPlaticaView Answer on Stackoverflow
Solution 3 - CssMD SHAYONView Answer on Stackoverflow
Solution 4 - CssSimon_WeaverView Answer on Stackoverflow
Solution 5 - CssOXiGENView Answer on Stackoverflow
Solution 6 - CssAndrewView Answer on Stackoverflow
Solution 7 - CssCiabarosView Answer on Stackoverflow