Sticky headers without JavaScript scroll listeners
The old way used JavaScript scroll events and getBoundingClientRect to toggle a class. Sticky positioning does it in one property.
2 position: sticky;
3 top: 0;
4}
2window.addEventListener('scroll', () => {
3 const rect = header.getBoundingClientRect();
4 if (rect.top <= 0) header.classList.add('fixed');
5 else header.classList.remove('fixed');
6});
7
8.header.fixed {
9 position: fixed;
10 top: 0;
11}
Browser Support for Sticky positioning
This feature is well established and works across many devices and browser versions. It has been available across browsers since 2022.
No JavaScript
The browser handles scroll. No listeners, no getBoundingClientRect, no class toggles.
Respects flow
Sticky stays in layout until it hits the threshold, then sticks. No layout jumps.
One property
Set position and top. Works for headers, sidebars, or any element you want to pin.
How it works
The old way meant a scroll listener, reading getBoundingClientRect on every scroll, and toggling a class to switch between normal and fixed. That's JS, reflows, and extra CSS for the fixed state.
With position: sticky and top: 0, the header stays in flow until it would scroll past the top, then it sticks. The browser does the work. No script, no class, no layout hacks.