01
Prefer position: sticky
A sticky header stays in the page flow, so it takes up its own space and still sticks to the top while scrolling. Content never starts underneath it.
header { position: sticky; top: 0; z-index: 50; }02
If it must be fixed, add matching space
Give the page top padding equal to the header height. A CSS variable keeps the two in sync when the header gets taller on phones.
:root { --header-h: 64px; }
@media (max-width: 767px) { :root { --header-h: 56px; } }
header { position: fixed; inset: 0 0 auto; height: var(--header-h); }
body { padding-top: var(--header-h); }Checklist
Questions
Why is my sticky header not sticking?
Usually an ancestor has overflow: hidden, overflow: auto or a fixed height. Sticky works relative to the nearest scrolling ancestor.
Fixed or sticky: which is better?
Sticky, in most cases: it keeps its space in the layout, so nothing slides underneath it.
How do I stop anchor links hiding under the header?
Add scroll-margin-top equal to the header height (plus a little breathing room) to the elements you link to.