DEV Community

loading...
Cover image for Stop Using Fixed Headers and Start Using Sticky Ones

Stop Using Fixed Headers and Start Using Sticky Ones

luisaugusto profile image Luis Augusto ・2 min read

Like them or not, headers that stay visible at the top of the page are a very popular UI and will likely not be going away anytime. Many sites make use of this kind of header, including Reddit, Facebook, Apple, and even DEV. What do each of these sites have in common? They are all using fixed headers.

I wanted to share that there is a better way to do this, and I am curious as to why no one is taking the approach of using a sticky header instead.

The issue with fixed headers

By using position: fixed on an element like the header, the element is removed from the stack and positioned relative to the browser window. That means it no longer takes up space and any elements positioned after it will adjust to fill up that area. In regards to a header, that means elements will be placed underneath it and you'll need to accommodate for it by using padding or relative positioning.

See Dev or Apple, which use a variable to store the header height and applies padding to the body or main tag:

Dev

Apple

Or Facebook, which uses relative positioning and a top offset to adjust for spacing:

Facebook

Or Reddit, which uses a margin to solve it instead:

Reddit

This is probably the worst way to build a header like because it's not responsive and extra unnecessary css. I suggest that headers like this should use sticky positioning instead.

The benefits of sticky positioning

By using position: sticky on a element like the header, it does a few great things. First of all, it doesn't remove the element from the stack, so it still keeps it's real estate in the container. That means you don't have to perform any of these hacks to get the right spacing for the main content and the header. Also, it still stays at the top of page or wherever you need it based on the scroll position. So instead of:

  • Setting header to position:fixed
  • Calculating the height with JS or manually adding it to a variable
  • Adjusting the position of the content with padding, margins, or relative positioning with that variable

All you have to do is:

header {
  position: sticky;
  top: 0;
}

And that's it, no extra variables or calculations needed.

Here is a very simple example in a Codepen:

Browser Support

Of course, the only downside is that it does not work on IE 11:

Can I Use Sticky Position

But really though, who is accessing the Apple website or Dev from IE11? Maybe I'm just crazy, but think there a few sites that can start making this transition over to sticky positioning.

Discussion (18)

pic
Editor guide
Collapse
marklchaves profile image
mark l chaves

Hi Luis,

Thanks for the article. Do you have a live code sample? I tried this a few times and I couldn't get it to work for me.

For example, in this pen, I disabled the CSS that compensates for my previous fixed header. Then, I changed my header to position sticky. No luck. All my anchors get hidden under the sticky header.

codepen.io/marklchaves/full/XWXgQJM

I checked to make sure my JS wasn't doing anything funky. I added the plain vanillla HTML anchor also just to make sure it wasn't my JavaScript.

What am I doing wrong?

Thanks!

Collapse
luisaugusto profile image
Luis Augusto Author

Hey Mark, thanks for reading! I took a look at the code and the sticky position does seem to be working, but are you referring to the tabs hiding under the header when you click on the anchor links? That is because anchor links will always bring that particular element to the very top of the page view, so regardless of whether you have a fixed or sticky header, it will always appear underneath when using an anchor link.

To get around anchor links jumping elements to the top of the page, you can add an offset to your #tabstrip element, like so:

#tabstrip {
  margin-top: -100px;
  padding-top: 100px;
}

I hope that helps!

Collapse
marklchaves profile image
mark l chaves

Got it. It's also my (mis)understanding of how sticky is supposed to work then. I appreciate that.

BTW, I use this snippet from SE to automatically compensate for fixed headers when using anchors.

:target::before {
    content: "";
    display: block;
    height: 6rem; 
    margin: -6rem 0 0; 
}

Thanks again!

Thread Thread
luisaugusto profile image
Luis Augusto Author

Awesome thanks for that, either way works!

Thread Thread
yujiri8 profile image
Ryan Westlund

Wow... that ::before solution is brilliant. I think I knew about the :target selector, but I'd completely forgotten. And here I was setting event handlers on load and hashchange to fix the scroll position.

(I think the ::before solution is better than #tabstrip because #tabstrip would get mess up background colors on a targeted element.)

There's still a minor issue, being that this doesn't account for a top bar with dynamic height, but I guess that's a small enough issue that I'll switch away from my kludgy JS :)

Collapse
dorshinar profile image
Dor Shinar

To be honest, I'm not a fan of either. I find it much simpler to use overflow-y: scroll on the element actually being scrolled (in DEV's case the articles), instead of fiddling with header position.

Collapse
pavelloz profile image
Paweł Kowalski

TBH on my computer DEV headers are not sticked/fixed/anything else.

Collapse
luisaugusto profile image
Luis Augusto Author

Sorry I didn't realize this when I wrote it, but looks like it's a setting in the UX options:

Collapse
pavelloz profile image
Paweł Kowalski

Ouh, that must be it :) I dont like things taking up vertical space so i probably turned it off long time ago and forgot :))

Collapse
waylonwalker profile image
Waylon Walker

I've been using headroom for a few months and like the simplicity (on my behalf) that it provides to make the nave hop in and out kinda like a more native mobile app.

showing it in action on waylonwalker.com

Here it is on waylonwalker.com

Collapse
luisaugusto profile image
Luis Augusto Author

Yea I also think this is a great approach, hiding the header when scrolling down and bringing it back when scrolling up. Easy to access and while still preserving screen real estate, and pretty easy to implement!

Collapse
iamshareque profile image
Shareque

I recently face this issue for a sidebar header,
the position:sticky act as draggable content on iPad where as position: fixed stick to given position, works normal.

Collapse
pavelloz profile image
Paweł Kowalski

I decided to write a post that adds on top of yours: dev.to/platformos/scrolling-to-the... :)

Collapse
luisaugusto profile image
Collapse
quodline profile image
Quodline

I prefer to hide the header when the user scrolls down and show it when the user scrolls up even slightly. I think it manages space better for small mobile phones.

Collapse
luisaugusto profile image
Luis Augusto Author

That's also a great option, and I'm done that for a few sites as well. You can also use sticky header in that situation and just animate its position with transform: translateY(-100%)

Collapse
detzam profile image
webstuff

Sooo sticky will let it hold the space in the dom, soi i won t need to add a margin top

Collapse
luisaugusto profile image