Click me to journey through the article.

HTML has always had the ability to jump to locations on a page, provided the target element has an id attribute, via a technique known as anchor links.

However, this movement is instantaneous. For the sake of appearance, a site's design sometimes calls for a smooth or slowed scroll to a point on a page.

Historically, this was achieved with JQuery, but it's overkill to load a framework just for one technique. Modern JavaScript provides a more efficient, native alternative, in the form of the window.scrollTo method.

A standard anchor link is used as the basis of the technique: that way, if the JavaScript doesn’t work for any reason, the page will still go to the targeted location.

<a href="#destination">Click me: I’m <em>smoooooth</em>.</a>
 <p id="destination">This is the target, further down the page.

Then, the body needs to have a scroll-behavior of smooth applied in CSS:

body {
	scroll-behavior: smooth;

Finally, the , added to the bottom so it doesn’t block execution on the rest of the page. I’ve expanded the code slightly from the promised five lines for clarity:

var anchorLink = document.querySelector("a[href^='#']");
var target = document.getElementById("destination");
anchorLink.addEventListener("click", function(el) {
    if (window.scrollTo) {
        window.scrollTo(0, target.offsetTop);

The querySelector uses a CSS attribute selector to find the first link that targets a URL beginning with #; clicking on this link initiates a test that the browser supports the scrollTo method. If it does, el.preventDefault stops the browser from immediately jumping to the anchor, and uses the scrollTo method to get there instead, smoothed by the earlier CSS declaration.

In comparison to a framework, this syntax is far simpler; the one downside is that it doesn’t allow the designer to change the timing function or scroll movement, to avoid abuses.

Abstracting the Script

The script as shown works well, but the approach demands that you know the name of the target in advance, and it can only be applied to one link. What if you want to have a series of links to different targets on the same page, with smooth scrolling between all of them? In that case, we need a little abstraction.

Because we’re referencing a nodeList, I’m going to start with a small helper function that will allow me to address the links in a forEach loop:

var forEach = function (array, callback, scope) {
  for (var i = 0; i < array.length; i++) {, i, array[i]);

Next, I’ll gather all the anchor links together, find what they address, and apply scrollTo when they are clicked on:

var anchorLinks = document.querySelectorAll("a[href^='#']");
if (window.scrollTo) {
    forEach(anchorLinks, function(index, element) {
        var target = document.getElementById(element.getAttribute("href").substring(1));
        element.addEventListener("click", function(el) {
            window.scrollTo(0, target.offsetTop); 

Note that this still requires scroll-behavior to be placed on the body tag.

Browser support

The one issue with this approach at this point in time is browser compatibility: window.scrollTo works in the latest versions of Chrome and Firefox, but not (yet) in Safari, Opera, or Internet Explorer. But because we’ve built the script on the principles of progressive enhancement, those browsers will still jump to the correct location on click using this script: they just won’t exhibit the smooth scroll behaviour.


This technique is often combined with elements that are are “sticky”, i.e. elements that scroll with the page until they reach the top of the viewport, where they “stick” in place. This is also commonly achieved with a framework, but modern CSS can accomplish it easily all by itself. I’ll cover that in the next article.