In the last 2 posts, I wrote about best practises around handling scroll events and then how to combine a sticky nav with smooth scrolling. Both solutions required JavaScript, but there's solutions right around the corner that allows us to do away with all the JavaScript and let the browser do all the work with a few directions from CSS.
UK EVENTAttend ffconf.org 2024
The conference for people who are passionate about the web. 8 amazing speakers with real human interaction and content you can't just read in a blog post or watch on a tiktok!
£249+VAT - reserve your place today
Firstly, I've replicated the ffconf2016 site and stripped out all the JavaScript that ran the smooth scrolling and sticky nav.
Then I turn to two CSS properties:
position: sticky
- currently supported in Firefox, Chrome and Safariscroll-behavior: smooth
- currently supported in Firefox only
The effect is exactly what I want and the final code is extremely light compared to the original JavaScript version.
Implementation details
The scroll-behavior
is applied directly on the html
element so that it applies to whole window scrolling.
The position: sticky
always catches me out. First I applied it to the navigation element, but this doesn't work because it's sticky to it's parent, and the parent doesn't have an inner scroll. The html
element is the element that's scrolling, so the stickiness is applied to the whole header element on the page (that includes the navigation bar).
Since the sticky is applied to the entire header block (which is the height of the page), the top
position for the sticky element, needs to be the height of the header element (100%
) less the height of the navigation (in my case 100px
). So I'm going to make use of the excellent CSS calc
value (which is very well supported): top: calc(-100% + 100px)
.
The final code is shown below. I've only applied it when the navigation is full present, in my case at > 768px
wide, and I've had to tweak the header component to use flex box to keep it set to the height of the window (note that this in only specific to my case, it's likely you wouldn't need this).
@media all and (min-width: 768px) {
html {
scroll-behavior: smooth;
}
#masthead {
position: sticky;
top: calc(-100% + 100px);
/* make sure stick above images */
z-index: 1;
/* tweaks to the ffconf design
to keep the height right */
display: flex;
flex-direction: column;
}
.logo-wrapper {
flex-basis: 85vh;
}
}
Full working demo here - currently only Firefox supports both position: sticky
and scroll-behavior
so it's best viewed there. But you can also see it working nicely (without enhancements) in Chrome and other browsers.