How to Fix CSS Position Sticky Not Working in a Flexbox?

An HTML element with CSS position: sticky applied might not work in a flexbox layout for the following reasons:

  1. Sticky Element Has Same or Larger Height Than Parent;
  2. Sticky Element Is Stretched to Same Height As Parent;
  3. No Threshold Is Specified;
  4. Overflowing Parent or Ancestor Doesn't Have Height.

If neither of these help you solve your issue, then you might want to check for browser compatibility and other common issues.

#Sticky Element Has Same or Larger Height Than Parent

Problem

If the sticky element's height is explicitly (or implicitly) set to an equal or larger value than its parent, then the sticky element ends up having no room for scrolling within its container. For example:

#parent { display: flex; gap: 5px; }
#parent > div { height: 200px; }
#sticky { position: sticky; top: 0; }

This will make all flex items the same height, producing an output like the following:

One
  height: 200px
Two
  height: 200px
position: sticky
  height: 200px

As you can see in this example, the sticky has no place to move within as it occupies the entire height of its container.

Solution

To make the sticky element stick to its container in this instance, you can do either of the following:

  1. Make the height of the sticky smaller, or;
  2. Make the height of the parent larger.

With either of the changes, the idea is to make room for the sticky element to move within. For example, you can make the height of the sticky element smaller than its parent when all flex items are explicitly set to the same height:

#parent { display: flex; gap: 5px; }
#parent > div { height: 200px; }
#sticky { height: 60px !important; position: sticky; top: 0; }

With these changes, the output will be like the following:

One
  height: 200px
Two
  height: 200px
position: sticky
  height: 60px

#Sticky Element Is Stretched to Same Height As Parent

Problem

Whenever the sticky element is stretched, it will occupy the entire height of its container, leaving no room for it to move within. This can be the case in the following scenarios:

#parent #sticky Description
align-items: normal
(default)
align-self: auto
(default)
These default values are implicitly set, and behave as stretch in a flexbox.
align-items: stretch align-self: auto
(default)
All flex items will compute to the parent's align-items value, and end up being enlarged to fill the container.
align-items: ... /* any value */ align-self: stretch align-self takes precedence, and consequently, the sticky item is stretched to fill the container.

You can see the result of applying these combinations in the following examples:

  1. When both, parent and sticky elements have the default value (i.e., align-items: normal and align-self: auto respectively), the sticky element is stretched:

    #parent
      align-items: normal
    One
    Two
    has
    extra
    text
    to
    stretch
    the
    container
    #sticky
      align-self: auto

    In this case, align-items: normal and align-self: auto are implicitly set if no other value is specified (as they're both default values):

    #parent { display: flex; gap: 5px; /* align-items: normal; */ }
    #sticky { /* align-self: auto; */ position: sticky; top: 0; }
    

    You can also explicitly set these values and have the same result:

    #parent { display: flex; gap: 5px; align-items: normal; }
    #sticky { align-self: auto; position: sticky; top: 0; }
    
  2. When the parent and the sticky element have align-items: stretch and align-self: auto respectively, then all flex items will compute to the parent's align-items value, and end up being stretched to fill the container:

    #parent
      align-items: stretch
    One
    Two
    has
    extra
    text
    to
    stretch
    the
    container
    #sticky
      align-self: auto

    In this case, align-self: auto is the default value for flex items, and is implicitly set if no other value is specified:

    #parent { display: flex; gap: 5px; align-items: stretch; }
    #sticky { /* align-self: auto; */ position: sticky; top: 0; }
    

    You can also explicitly set flex items to align-self: auto to the same effect:

    #parent { display: flex; gap: 5px; align-items: stretch; }
    #sticky { align-self: auto; position: sticky; top: 0; }
    
  3. When the sticky element has align-self: stretch, it takes precedence over parent's align-items value, resulting in the sticky element being stretched to fill the container, like so:

    #parent
      align-items: center
      height: 200px
    One
    Two
    #sticky
      align-self: stretch

    For example:

    #parent { display: flex; gap: 5px; align-items: center; }
    #sticky { align-self: stretch; position: sticky; top: 0; }
    

Solution

In these cases, you need to make sure the sticky element is not stretched, i.e.:

  1. It has a value other than align-self: stretch, or;
  2. When it is set to align-self: auto (default), the parent is not set to align-items: normal (default), or align-items: stretch.

To fix issues with the previously shown stretched sticky elements, you can, for example, simply set align-self: start on the sticky elements to make them appear at the start and avoid them from being stretched:

  1. #parent
      align-items: normal
    One
    Two
    has
    extra
    text
    to
    stretch
    the
    container
    #sticky
      align-self: start
  2. #parent
      align-items: stretch
    One
    Two
    has
    extra
    text
    to
    stretch
    the
    container
    #sticky
      align-self: start
  3. #parent
      align-items: center
      height: 200px
    One
    Two
    #sticky
      align-self: start

#No Threshold Is Specified

Problem

To ensure proper behavior in sticky positioning, you need to define a threshold to a value other than "auto" using at least one of the following: top, right, bottom, or left.

If a threshold isn't specified for the sticky element, its behavior becomes indistinguishable from relative positioning, as you can see in the following example:

One
Two
#sticky
  top: auto

Solution

If you specify a threshold, for example, by setting top to a value other than auto, then the sticky will flow within its container till it meets the opposite edge of its containing block:

One
Two
#sticky
  top: 10px

#Overflowing Parent or Ancestor Doesn't Have Height

Problem

The sticky element won't move within its parent if the parent or any of its ancestors compute to an overflow property other than overflow: visible — i.e., one of the following:

  1. overflow: hidden
  2. overflow: scroll
  3. overflow: auto

For example:

#parent
  overflow: auto
One
Two
has
extra
text
to
stretch
the
container
#sticky
  align-self: start

Learn more about why position: sticky does not work with the CSS overflow property and how to fix it.

Solution

In such a case, you must specify a height on the overflowing container, which in this case is the parent of the sticky element:

#parent
  height: 100px
  overflow: auto
One
Two
has
extra
text
to
stretch
the
container
#sticky
  align-self: start

This post was published (and was last revised ) by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.