• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
JavaScriptSource

JavaScriptSource

Search 5,000+ Free JavaScript Snippets

  • Home
  • Browse Snippets
    • Addon
    • Ajax
    • Buttons
    • Cookies
    • CSS
    • Featured
    • Forms
    • Games
    • Generators
    • Image Effects
    • Math Related
    • Miscellaneous
    • Multimedia
    • Navigation
    • Page Details
    • Passwords
    • Text Effects
    • Time & Date
    • User Details
Home / Navigation / Scroll to an element smoothly (smooth scroll)

Scroll to an element smoothly (smooth scroll)

Scroll to an element smoothly (smooth scroll)

We can scroll to given element smoothly (smooth scroll) by passing behavior: 'smooth':

ele.scrollIntoView({ behavior: 'smooth' });

or applying the CSS property scroll-behavior to the target element:

scroll-behavior: smooth;

Both methods aren’t supported in IE and Safari, and don’t allow to customize the animation.

This post introduces a smoothly scroll implementation which also allows us to customize the animation effect and duration. We’ll demonstrate in a popular use case that user can jump between sections by clicking associated navigation button.

The navigation consists of some a elements:

<a href="#section-1" class="trigger"></a>
<a href="#section-2" class="trigger"></a>
...

<div id="section-1">...</div>
<div id="section-2">...</div>

Clicking the link will scroll the page to a particular element that can be determined by the href attribute.

const triggers = [].slice.call(document.querySelectorAll('.trigger'));
triggers.forEach(function (ele) {
    ele.addEventListener('click', clickHandler);
});

The clickHandler function handles the click event of a navigation element. It determintes the target section based on the href attribute. Notice that we will scroll to the target section ourselves, hence the default action will be ignored:

const clickHandler = function (e) {
    // Prevent the default action
    e.preventDefault();

    // Get the `href` attribute
    const href = e.target.getAttribute('href');
    const id = href.substr(1);
    const target = document.getElementById(id);

    scrollToTarget(target);
};

Don’t worry if you haven’t seen the scrollToTarget function. As the name implies, the function will scroll the page to given target.

Scroll to given target

It is the main part of the post. To scroll to given point, we can use window.scrollTo(0, y) where y indicates the distance from the top of the page to the target.

What we’re going to do is to move from the starting point to the ending point in given duration.

  • The starting point is the current y-axis offset, window.pageYOffset
  • The ending point is the top distance of the target. It can be retrieved as target.getBoundingClientRect().top
  • The duration is a number of milliseconds. You can change it to a configurable option, but in this post, it’s set as 800.
const duration = 800;

const scrollToTarget = function (target) {
    const top = target.getBoundingClientRect().top;
    const startPos = window.pageYOffset;
    const diff = top;

    let startTime = null;
    let requestId;

    const loop = function (currentTime) {
        if (!startTime) {
            startTime = currentTime;
        }

        // Elapsed time in miliseconds
        const time = currentTime - startTime;

        const percent = Math.min(time / duration, 1);
        window.scrollTo(0, startPos + diff * percent);

        if (time < duration) {
            // Continue moving
            requestId = window.requestAnimationFrame(loop);
        } else {
            window.cancelAnimationFrame(requestId);
        }
    };
    requestId = window.requestAnimationFrame(loop);
};

As you see, we tell the browser to execute the loop function before the next paint happens. At the first time, startTime will be initialized as the current timestamp (currentTime).

We then calculate how many milliseconds has gone:

const time = currentTime - startTime;

Based on the elapsed time and the duration, it’s so easy to calculate the number of percentages we have been moving, and scroll to that position:

// `percent` is in the range of 0 and 1
const percent = Math.min(time / duration, 1);
window.scrollTo(0, startPos + diff * percent);

Finally, if there’s remaining time, we continue looping. Otherwise, we cancel the last request:

if (time < duration) {
    // Continue moving
    requestId = window.requestAnimationFrame(loop);
} else {
    window.cancelAnimationFrame(requestId);
}

Customize the animation

Currently, we move to the target equally per millisecond. We move the same distance every milliseconds.

If you want, you can replace the current linear movement with other easing functions. Look at this website to imagine how each easing produces different animations.

The code below uses the easeInQuad animation:

const easeInQuad = function(t) {
    return t * t;
};

const loop = function(currentTime) {
    ...
    const percent = Math.min(time / duration, 1);
    window.scrollTo(0, startPos + diff * easeInQuad(percent));
});

Source

https://htmldom.dev/scroll-to-an-element-smoothly/

Navigation

Related Snippets:

  • Detecting when a visitor has stopped scrolling
  • Check if touch events are supported
  • Using the Target Attribute
  • Drag to scroll

Primary Sidebar

Popular Posts

Story Generator

IP Grabber – get a users IP address with JavaScript

Simple Calendar

Remove Ads

Astrological Calculator

Copyright © 2025 JavaScriptSource.com

  • About
  • Privacy Policy
  • FAQ
  • Jobs For Developers