How to Fix Issues With CSS Position Sticky Not Working?

The CSS position: sticky may not work for a number of reasons. You can consider the following checklist to address potential issues:

  1. Check for Browser Compatibility;
  2. Check if a Threshold Has Been Specified;
  3. Check if Parent or Ancestor Element Has overflow Property Set;
  4. Check if Sticky Has Enough Room to Scroll Within;
  5. Check if the Sticky Element Stretches Inside a Flexbox;
  6. Check for Overriding Rules.

#Checking for Browser Compatibility

Check that the browser you're using supports position: sticky.

Known Issues

  1. Missing Vendor Prefix For Safari 13 and Below

    In Safari 13 and below, a vendor prefix (-webkit-sticky) is required in addition to position: sticky:

    .sticky {
      position: -webkit-sticky;
      position: sticky;
      top: 0;
    }
    
  2. Sticky Table Headers Issue

    Firefox 58 & below, Chrome 63 & below and Safari 7 & below do not appear to support sticky table headers:

    div { width: 500px; height: 75px; overflow: auto; }
    table { width: 100%; border-collapse: collapse; table-layout: fixed; }
    
    thead {
      color: #fff;
      position: sticky;
      top: 0;
      background-color: #444;
    }
    
    tbody { height: 50px; }
    tbody td { border: 1px solid #ccc; }
    

#Check if a Threshold Has Been Specified

A sticky element requires a threshold to be specified for properties like top, right, bottom, and left. The threshold value that you set, will make the sticky element act as fixed positioned when it crosses the specified threshold, and a relatively positioned element otherwise. You can see in action in the following example:

One
Two
#sticky
  top: 0

Failure to set a threshold can make the sticky element behave similarly to relative positioning:

One
Two
#sticky
  top: auto

Therefore, you must set a value other than "auto" for at least one of, top, right, bottom, or left properties for position: sticky to work. For example:

.sticky {
  position: sticky;
  top: 0;
}

#Check if Parent or Ancestor Element Has overflow Property Set

If a parent or ancestor of the sticky element has overflow: hidden, overflow: scroll, or overflow: auto, the sticky might not work. You can see this issue in the following example:

#parent
  overflow: auto
One
Two
has
extra
text
to
stretch
the
container
#sticky

To diagnose and fix this issue, you can do the following:

  1. Find Parent or Ancestors With overflow Property Set

    You can copy/paste the following snippet in your browser's web developer console to identify all parent/ancestor elements with overflow property set to something other than visible:

    let parent = document.querySelector('.sticky').parentElement;
    
    while (parent) {
      const hasOverflow = getComputedStyle(parent).overflow;
      if (hasOverflow !== 'visible') {
        console.log(hasOverflow, parent);
      }
      parent = parent.parentElement;
    }
    
  2. Add a height for the Overflowing Container

    By specifying a height on the overflowing container(s) you identified in the previous step, you should be able to make position: sticky work without having to remove the overflow property from the container element.

    Consider, for example, the following where setting the height on the overflowing element (e.g., "#parent") fixes the issue:

    #parent { height: 100px; overflow: auto; }
    #parent > div { display: inline-block; vertical-align: top; }
    #sticky { position: sticky; top: 0; }
    

For detailed explanation and examples, check out the post about fixing CSS position: sticky not working with overflow.

#Checking if Sticky Has Enough Room to Scroll Within

If the sticky element does not have enough room to scroll within, it won't work. This could be the case when:

  1. Sticky Element Has Same or Larger Height Than the Parent

    #parent { display: inline-block; }
    #parent > div { height: 200px; }
    #sticky { position: sticky; top: 0; }
    

    This will make all children of "#parent" (including the sticky element) the same height, producing an output like the following:

    One
      height: 200px
    Two
      height: 200px
    position: sticky
      height: 200px
  2. Sticky Element Is Stretched to Same Height as Parent

    #parent { display: inline-block; height: 200px; }
    #sticky { height: 200px; position: sticky; top: 0; }
    

    This will make the sticky and the parent element the same height, producing an output like the following:

    #parent
      height: 200px
    One
      height: auto
    Two
      height: auto
    position: sticky
      height: 200px

In these cases the sticky element ends up having no room for scrolling within its container. Therefore, to make the sticky work in these instances, you can make the height of the sticky smaller, or make the height of the parent larger. For example:

#parent { display: inline-block; }
#parent > div { height: 200px; }
#sticky { height: 60px !important; position: sticky; top: 0; }

This will make the height of the sticky element smaller than its siblings, giving it room inside its container to stick within:

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

As a rule of thumb, the parent element should always have a larger height than the sticky element for it to work.

#Checking if the Sticky Element Stretches Inside a Flexbox

If sticky element's parent is a flexbox, then you must make sure that it does not stretch to occupy the entire height of its container. Otherwise, it will leave no room for it to move within. This can be the case in the following scenarios:

  1. Parent Has align-items: normal and Sticky Has align-self: auto

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

    The flex parent and sticky element default to align-items: normal and align-self: auto respectively. So, when you implicitly or explicitly specify these values, position: sticky won't work:

    #parent
      align-items: normal
    One
    Two
    has
    extra
    text
    to
    stretch
    the
    container
    #sticky
      align-self: auto
  2. Parent Has align-items: stretch and Sticky Has align-self: auto

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

    When the flex parent explicitly has align-items: stretch and the sticky element implicitly or explicitly has align-self: auto set, position: sticky won't work:

    #parent
      align-items: stretch
    One
    Two
    has
    extra
    text
    to
    stretch
    the
    container
    #sticky
      align-self: auto
  3. When Sticky Has align-self: stretch

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

    When the sticky element is has align-self: stretch set, it takes precedence over parent's align-items value, resulting in the sticky element being stretched to fill the container. This leaves no room for sticky to scroll within:

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

To fix all these issues, you can simply set the value of the align-self property of the sticky element to a value that does not make it stretch. For example, you could set align-self to flex-start, making the sticky element position at the start and not be stretched:

#parent
  align-items: normal
  height: 200px
One
Two
#sticky
  align-self: flex-start

For detailed explanation and examples, check out the post about fixing CSS position: sticky not working in a flexbox.

#Checking for Overriding Rules

You can make sure that the element you are applying the position: sticky property to is not being overridden by a more specific selector.

For example, consider the following HTML/CSS:

<div id="parent">
  <div id="child-1">Foo</div>
  <div id="child-2">Bar</div>
</div>
#child-1 {
  position: sticky;
  top: 0;
}

It could be the case, for example, that another CSS selector with higher specificity is overriding your selector and the CSS style rules on the element, such as the following:

#parent #child-1 {
  position: relative;
}

To fix this, you can either remove the more specific selector, or make your selector more specific than the other one.


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.