Smooth Scrolling

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Hey! Before you go too far down the rabbit hole of JavaScript-based smooth scrolling, know that there is a native CSS feature for this: scroll-behavior.

html {
  scroll-behavior: smooth;

And before you reach for a library like jQuery to help, there is also a native JavaScript version of smooth scrolling, like this:

// Scroll to specific values
// scrollTo is the same
  top: 2500, 
  left: 0, 
  behavior: 'smooth'

// Scroll certain amounts from current position 
  top: 100, // could be negative value
  left: 0, 
  behavior: 'smooth' 

// Scroll to a certain element
  behavior: 'smooth' 

Dustan Kasten has a polyfill for this. And you’d probably only reach for this if you were doing something with scrolling the page that couldn’t be done with #target jump links and CSS.

Accessibility of Smooth Scrolling

Whatever technology you use for smooth scrolling, accessibility is a concern. For example, if you click a #hash link, the native behavior is for the browser to change focus to the element matching that ID. The page may scroll, but the scrolling is a side effect of the focus changing.

If you override the default focus-changing behavior (which you have to, to prevent instant scrolling and enable smooth scrolling), you need to handle the focus-changing yourself.

Heather Migliorisi wrote about this, with code solutions, in Smooth Scrolling and Accessibility.

Smooth Scroll with jQuery

jQuery can also do this. Here’s the code to perform a smooth page scroll to an anchor on the same page. It has some logic built in to identify those jump links, and not target other links.

// Select all links with hashes
  // Remove links that don't actually link to anything
  .click(function(event) {
    // On-page links
    if (
      location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') 
      location.hostname == this.hostname
    ) {
      // Figure out element to scroll to
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
      // Does a scroll target exist?
      if (target.length) {
        // Only prevent default if animation is actually gonna happen
        $('html, body').animate({
          scrollTop: target.offset().top
        }, 1000, function() {
          // Callback after animation
          // Must change focus!
          var $target = $(target);
          if ($":focus")) { // Checking if the target was focused
            return false;
          } else {
            $target.attr('tabindex','-1'); // Adding tabindex for elements not focusable
            $target.focus(); // Set focus again

If you’ve used this code and you’re all like HEY WHAT’S WITH THE BLUE OUTLINES?!, read the stuff about accessibility above.

Smooth Scrolling in React

James Quick has a nice step-by-step tutorial on how to implement smooth scrolling in React using the react-scroll plugin: