You might not need Javascript for that: Position Sticky

This post is the first of a new series called “You might not need Javascript for that” which focuses on how CSS can be used to replace Javascript in certain causes. While I have nothing against Javascript (I actually prefer writing JS to CSS most days), I’ve been pleasantly surprised with the power of CSS in the last few months and would like to share what I’ve learned.

This specific post aims to provide a quick intro to position: sticky, a powerful attribute that I didn’t know about until recently. It works a bit like position: absolute except that it will ‘stick’ to the viewport instead of scrolling up like a normally positioned element. This is hard to explain with words, so please check out my demo below to see what I mean.

1

Pretty cool, right?

Support

I think that browser support of sticky positioning might be described best as ‘decent’, but not ‘good’. As of today, it looks something like this:

So basically it doesn’t work on IE or Edge, but I’m cool with that for two reasons:

  1. It will fail somewhat gracefully in most cases
  2. There are javascript based polyfills available that are easy to use. I’ve had good luck using StickyFill.

Now we’ve covered what position: sticky does and that it can be used across browsers, but why is it so useful? What is wrong with using Javascript for this kind of thing? Well solving this problem with Javascript is somewhat of a headache… let’s imagine implementing the design shown in the above codepen in Javascript – these would be the steps:

  1. First you need to know the height of the top header that is not sticky, which probably involves diving into the DOM. You could also set the height explicitly with CSS and just reference that number in Javascript, but that approach is not maintainable. You might also need to setup event listeners (like onresize) to update the height for a smaller mobile header.
  2. You will also need to track the distance that the sticky header is from the top of the viewport. This could be done with a throttled onscroll event, but your framerate could get ugly. Setting up a recursive requestAnimationFrame will probably give you the best UX in the end.
  3. Now you need to do the math to actually figure out if the sticky header is at the top or not, and set its position to fixed when it is.

I think you can see what I am getting at – writing custom Javascript to do this kind of thing is a bit of a drag (and definitely hurts developer productivity). Another option is to use an established library to do this for you. The downsides of this are:

  1. In my experience, the animation in which the elements transitions from scrollable to sticky just looks better with CSS. I’m sure this depends on what library you are using, however.
  2. I’ve had bad luck with bugs. In one case a new release of chrome caused a really strange bug for some users in the library I was using, which I never could recreate or solve. Eventually I just dropped the library and used a different solution.

All in all, I’m pretty excited that I came across this little CSS attribute and see myself using it a lot in the future.