ele.scrollIntoView[{ behavior: 'smooth' }];
or applying the CSS property scroll-behavior to the target element:
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:
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];
const clickHandler = function [e] {
const href = e.target.getAttribute['href'];
const target = document.getElementById[id];
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.
It's also possible to set behavior: 'smooth':
window.scrollTo[{ top, left, behavior: 'smooth' }];
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 scrollToTarget = function [target] {
const top = target.getBoundingClientRect[].top;
const startPos = window.pageYOffset;
const loop = function [currentTime] {
const time = currentTime - startTime;
const percent = Math.min[time / duration, 1];
window.scrollTo[0, startPos + diff * percent];
requestId = window.requestAnimationFrame[loop];
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:
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:
requestId = window.requestAnimationFrame[loop];
window.cancelAnimationFrame[requestId];
Customize the animation
Currently, we move to the target equally per millisecond. We move the same distance every milliseconds.
The code below uses the easeInQuad animation:
const easeInQuad = function[t] {
const loop = function[currentTime] {
const percent = Math.min[time / duration, 1];
window.scrollTo[0, startPos + diff * easeInQuad[percent]];
In the following demo, try to move between sections by clicking an circle on the left.
Demo
Scroll to an element smoothly