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:
-
You are not specifying at least one of the CSS properties:
top
,left
,right
orbottom
. 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 -
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;
-
Internet Explorer, Edge 15 and earlier versions do not support sticky positioning
-
The parent element does not have it
height
orposition:relative
specified. This would need to apply to all parent elements of the sticky element and not just the immediate ancestor. -
The parent element, such as a
div
is using theflex
display. We need to also set the sticky element to havealign-self: flex-start
. -
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 notthead
ortr
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.