Smooth scrolling using CSS

More than 9 years ago, I wrote a (German only) blog post about how to “improve JavaScript with scroll event handlers”. Back in the days, people would use a plugin like “WP-Smooth-Scroll” (it’s still around, but hasn’t been updated in 11 years). Smooth scrolling was often used in combination with a “scroll to top button”. The scroll effect was done with the scrollTop() function from jQuery. Nowadays, jQuery is not used as much. But scrolling with JavaScript is still around.

Scrolling a page with JavaScript

Beside “scroll to top buttons”, a website can also use “smooth scrolling” for anchors. If you want to see it in action, look no further than on the file wp-includes/js/admin-bar.js in WordPress core, where you will find this function:

/**
 * Scrolls to the top of the page.
 *
 * @since 3.4.0
 *
 * @param {Event} event The Click event.
 *
 * @return {void}
 */
function scrollToTop( event ) {
	// Only scroll when clicking on the wpadminbar, not on menus or submenus.
	if (
		event.target &&
		event.target.id !== 'wpadminbar' &&
		event.target.id !== 'wp-admin-bar-top-secondary'
	) {
		return;
	}

	try {
		window.scrollTo( {
			top: -32,
			left: 0,
			behavior: 'smooth'
		} );
	} catch ( er ) {
		window.scrollTo( 0, -32 );
	}
}

As you can see from the comment, this function has been around since WordPress 3.4, which was released in June 2012! The behavior: 'smooth' was added only later, since Firefox added it in 2015 and Chrome in 2017. But still today, you can click on the “Admin Bar” (on anything but a link) and the website will scroll up smoothly.

The issue with method

As we can see in the code above, the scrollTo() function takes an object with the exact scroll position in the viewport. For the WordPress “Admin Bar”, this is easy, since it sticks to the top of the page. But if we want to scroll to another element on the page using an anchor link, we need to calculate the position. And do you remember our last blog post on the CSS topic, “How to fix sticky headers“? If we want to make sure the scroll position is correct, we also need to take the scroll-margin-top offset into account.

An alternative JavaScript approach

There is another scrolling function, that is also around for many years: the scrollIntoView() function. With this one, we don’t have to calculate the position. We just select the element we want to scroll to and use this function on it:

const element = document.getElementById("some-anchor");
element.scrollIntoView();

The great thing about this one, is that you can even tell the function where to place the element. And it takes the scroll-margin-top or similar properties into account. There are some more examples on the documentation page. One of these other CSS properties is the one, I want to write about in this blog post.

The CSS scroll-behavior

Even without JavaScript, you can get a smooth scrolling by only using CSS. Just add the following to your page:

html {
	scroll-behavior: smooth;
}

Now, when you click on any anchor link, the site will “scroll smoothly” to that element. And since the browser knows exactly how to do that, we always get the perfect scroll position for that element.

Conclusion

Sure, you can use a function with 20 lines like in WordPress Core for a smooth scrolling effect. But you could also just use one CSS property and regular anchor links to get the same result. And I haven’t even told you about all the issues with JavaScript scrolling, like scrolling manual scrolling while the smooth scrolling is still animating, wrong position calculation due to lazy loading, etc. I hope this is enough to convince you for now. 😉

2 comments » Write a comment

  1. Nice post, Bernhard. It’s interesting to see how complex JS solutions have been replaced with CSS one-liners. Related, scroll-padding-top and scroll-margin-top are very handy CSS properties.

Leave a Reply

Your email address will not be published. Required fields are marked *