How to get sticky elements to stick

Sticky elements are used to persist context to make information easier to understand. They commonly appear in navigation, tables and tooltips. Outside of web development, sticky elements are also widely known as frozen rows or columns, thanks to Excel.

When the CSS position: sticky property was introduced, many developers thought it would make sticking elements much easier, and it did, for most parts. There are times where it doesn't, and debugging those scenarios are often an exercise of frustration.

In this tutorial, we will learn what makes sticky elements stick, and how you can debug your stuck element.

How sticky works

First, a sticky element requires a parent container, which is the nearest scrollable container. The parent container defines the boundaries of the sticky element, preventing the element from going beyond the parent container.

Secondly, position: sticky works as a position: relative until it crosses a threshold and is treated as a position: fixed.

position
.child {
    position: sticky;
    top: 0;
    left: 50px;
}
1
sticky
2
3

Debugging sticky

Check element for position offset properties

In order for the sticky element to stick, it needs to act as a position: fixed element when it passes the threshold, which requires one of the top, right, bottom, left properties to be declared.

Check the element's height

When the sticky element's height is more than the viewport, it will not have any opportunity to go pass the threshold to act as a position: fixed element. Set a max-height property to ensure it stays within the viewport height.

height
.child {
    position: sticky;
    top: 0;
    left: 50px;
    height: auto;
}
sticky
1
2

Check parents for overflow

When parent elements of the sticky element have an overflow property set to hidden, scroll or auto, they become the new scrollable context. When this scrollable context does not scroll, visually it looks like the sticky element has stopped working.

overflow
height
.parent {
    overflow: visible;
    height: auto;
}
.child {
    position: sticky;
    top: 0;
    left: 50px;
}
sticky
1
2

There are three ways to resolve this:

  1. Set the overflow property to visible.
  2. Give the parent element a height.
  3. Set the overflow property to clip. (Limited browser support. Only Chrome 90 supports this at time of writing.)

If all else fails

If the above steps do not work for you, perhaps you have reached the limits of what position: sticky can do for you. JavaScript solutions may be required and there are plenty of well tested libraries to try out. Alternatively, you could take on the challenge of writing your own by changing CSS styles with the use of an IntersectionObserver.