The Gotchas of `position: sticky`

position: sticky is an excellent newer CSS property for working with designs where an element needs to stick to point a page as a user scrolls down. This allows us to replace large amounts of legacy JS and bring styling of sticky elements back into CSS. 

However, position: sticky has a lot of gotchas and they’re not well documented in one particular place. I recently had to add sticky positioning on a new theme build and encountered quite a few issues with un-documented issues – this post is an attempt to document all of the potential gotchas and make your life easier.

What is position: sticky?

Position sticky is a relatively new CSS attribute that allows an element to stick to a particular point on the page when the window scrolls to {n} pixels above or below that element. Previously a developer would have had to use JS to swap classes or styles dynamically to achieve this affect, but we can do this with just 2 lines of CSS.

For example: 

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

In the below example, as you scroll down the page, the alphabetical headers stay stuck to the top of the parent element until the next header is in position.

See the Pen Sticky positioning by Šime Vidas (@simevidas) on CodePen.

Read more at the MDN positioning docs.

The most important thing to remember about sticky positioning is that it is heavily reliant on the element’s parent. The sticky item stops and ends at the limits of the parent element, so most of the issues with sticky come from styling at a parent or ancestor element.

Most of the issues documented below come back to this core principle of the parent styles.

Elements must have top, left, right, or bottom values

This is the most documented issue with position: sticky. The element being stuck, must have at least one of  top, left, bottom, and/or right values. This is so that the browser knows when to stick the element as a user scrolls down the page. None of these values can be auto and if top is set, bottom is ignored.

An ancestor must not have some overflow values

If an ancestor element is using overflow: hidden, overflow: auto, or overflow:scroll in its styles, the browser will not be able to effectively calculate the height and limits of the ancestor element and sticky will not work properly.

This is because the positioning is calculated from both the height of the parent and the nearest scrollable container. 

The box’s position depends on its containing block(established as for position:static) as well as its scrolling container, defined by the nearest ancestor in the same document with a computed value for overflow-x or overflow-y other than visible, or the viewport if no such ancestor exists.

Corey Ford

Must have a parent with enough height to scroll

Since an element starts and ends becoming sticky at the limits of the parent element, an element can only stick within the height of the parent element. If you are trying to “stick” an element that is the same height as its parent – the element simply won’t move. 

If you’re trying to stick an element within a parent that is the same height, you need to apply position: sticky to the parent element instead.

Browser support is good, but not perfect

Most modern browsers have position: sticky available in-built. However, if you need to support IE11 or backwards, you need to add a polypill or do some additional work to get the effect duplicated. Stickybits is a well-supported alternative and smaller than most polyfills.

Data on support for the css-sticky feature across the major browsers from caniuse.com