Fixing CSS position sticky not working issues

Position:sticky CSS property is commonly used to create sticky headers or footers. We will go over a few problems and solutions when using this property.

Nov 30, 2022 | Read time 7 minutes

🔔 Table of contents

There are several possible solutions to fix position:sticky not working in CSS. This is depending on the source of the issue. Here are some suggested steps to try:

  1. You are not specifying at least one of the CSS properties: top, left, right or bottom. Be careful though if you specify more than one of those. If both left and right are specified, left wins. Likewise, if top and bottom are used at the same time, top wins - Based on this bug

  2. For not working in Safari browsers, you are not specifing the -webkit-sticky browser prefix. To be sure that you have covered all browsers, we can use the following declaration:

position: -webkit-sticky;
position: -moz-sticky;
position: -o-sticky;
position: -ms-sticky;
position: sticky;
  1. Internet Explorer, Edge 15 and earlier versions do not support sticky positioning

  2. The parent element does not have it height or position:relative specified. This would need to apply to all parent elements of the sticky element and not just the immediate ancestor.

  3. The parent element, such as a div is using the flex display. We need to also set the sticky element to have align-self: flex-start.

  4. If the previous options are not working, it could be due to your z-index. Try adding a z-index property to your sticky element with a value greater than 0. This will help ensure that your element is above any other elements on the page.

What is the position:sticky anyway?

Elements that are defined with position sticky are positioned normally based on the document flow. It will then “stick” with its nearest parent element’s scroll behaviour.

Below is a demo of how it should behave:

We can lay it out as follows:

<div class="main">
  
  <p>Some example text..</p>
  <div class="sticky">I will stick to the screen when you reach my scroll position
  </div>

  <div>
   ... lots of content ..
  </div>
</div>
.main{
  position:relative;
}

.sticky {
  position: sticky;
  top: 0;
  background-color: yellow;
  padding: 50px;
  font-size: 20px;
}

Check if using position:sticky with flex

When the parent element of a position sticky element is set as flex display, this will not work unless you have set the right CSS properties.

Consider the following HTML and CSS, we have the main element as display:flex and we want to make the child yellow element sticky

<div class="main">
  
  <p>Some example text..</p>
  <div class="sticky">I will stick to the screen when you reach my scroll position
  </div>

  <div>
   ... lots of content ..
  </div>
</div>
.main{
    display:flex;
    flex-direction:row;
    justify-content:center;
}

div.sticky {
  position: sticky;
  top: 0;
  background-color: yellow;
  padding: 50px;
  font-size: 20px;
}

This results in the above - we can see that the yellow element is not sticking at all. It just takes the height of the main element.

Since flex box elements default to stretch, all the elements are the same height - which does not allow scrolling and thus the sticky behaviour would not kick in.

Adding align-self: flex-start to the sticky element set the height to auto, which allowed scrolling will fix it. The align-self: flex-start property overrides the flex item’s align-items value. In this case we use flex-start which put the flex item at the start of the parent.

.main{
    display:flex;
    flex-direction:row;
    justify-content:center;
}

div.sticky {
  position: sticky;
  top: 0;
  height: auto; /* <- ADD HERE */
  background-color: yellow;
  padding: 50px;
  font-size: 20px;
  align-self: flex-start; /* <- ADD HERE */
}

Check Position:sticky with overflow (hidden, scroll or auto)

On the parent of the sticky element, AVOID using overflow:hidden, overflow:scroll, or overflow:auto.

Since sticky elements rely on the scrolling of the parent element - modifying overflow behaviour will break this.

However using overflow:visible or overflow:clip should be fine to keep your sticky elements desired behaviour.

Safari browser support for position:sticky

Support for position:sticky is widespread for most of the modern browsers (Chrome, Firefox, Edge, etc) however there are some cases we will need to consider. For Safari browsers, its best to use the vendor prefixes (-webkit-sticky):

position: -webkit-sticky;
position: -moz-sticky;
position: -o-sticky;
position: -ms-sticky;
position: sticky;

There are other support issues that we need to consider when using this position:sticky:

  • No support for IE 11 or lower versions
  • Supported on th elements, but not thead or tr in Edge/Chrome
  • Do not appear to support sticky table headers

The Javascript (old method)

We can use Javascript to mimic the same behaviour as position:sticky. This can be handy when you want to support older browsers such as IE or older versions of Safari.

The idea is to have a event listener on the scroll. As the user moves out of the viewport (scroll down), we apply a position:fixed to that element we want to stick.

As the user scrolls up and goes back into the view, we remove the position:fixed styling.

<div class="header"></div>

<script>
var header = document.querySelector('.header');
var origOffsetY = header.offsetTop;

// run this scroll function to check the window scrollY vs the header's scrollY value
function onScroll(e) {
    window.scrollY >= origOffsetY ? header.classList.add('sticky') :
                                    header.classList.remove('sticky');
}

document.addEventListener('scroll', onScroll);
</script>

This method is not prefered since it can make your page look janky since processing is done on the CPU side.

Using the default position sticky will shift process to the GPU (Graphical Processing Unit) and will appear more smooth.

Summary

Position sticky CSS property is commonly used for navigation or footers - making them stick to the viewport as the user scrolls. There are several solutions or things to check when you have encountered problems trying to implement this. Some steps we can go through includes:

  • check the top, left, right and bottom is set,
  • check the browser support - or use JavaScript if you want to support legacy browsers such as IE
  • check that the parent is using flex or not - if flex is used, then the sticky element needs to have align-self:flex-start
  • Make sure you are NOT using any overflow properties on the parent.

👋 About the Author

G'day! I am Huy a software engineer based in Australia. I have been creating design-centered software for the last 10 years both professionally and as a passion.

My aim to share what I have learnt with you! (and to help me remember 😅)

Follow along on Twitter , GitHub and YouTube