How to create smooth scroll for your website

It is normal for website to have smooth scroll, but do you know how to create your own smooth scroll without using any plugins?

For modern browsers, you can use different way to customize the behaviour of smooth scroll!

Native method: scrollIntoView

scrollIntoView is JavaScript method that supported by modern browsers, like Chrome, Firefox and Edge. The usage is simple, just like this:

function scroll(e) {
e.scrollIntoView({behavior: "smooth", block: "start"});
}
scroll(document.getElementById(YOUR_DIV_ID));

behavior means what behaviour you want during scrolling. You can choose between ‘auto’, ‘smooth’ and ‘instant’. If you choose instant, it will instantly jump to that section, just like <a href="#knowmore">Know More</a>.

block means the end position of target. You can choose between ‘start’, ‘center’, ‘end’ and ‘nearest’. The default value is ‘center’. which means after scrolling, its position will be the center of the div.

To simulate the effect of anchor tag, we choose ‘top’ here.

For more options, you can view from MDN.

Piece of cake, right? However, IE 11 and Safari do not support options, which mean even you have setup behavior: “smooth”, it would still instantly jump to that position.

That is not ideal for our smooth scroll, so here is another solution.

Custom method: requestAnimationFrame

requestAnimationFrame is another method for creating smooth scroll. It is hard to understand how it works at first sight. Here are my understandings:

  1. It uses step, which means you need to call the function again (that means you need to trigger the next step manually)
  2. Generates timestamp at each step, so you can use the timestamp to cancel the animation (somehow equals to clearInterval)
  3. Better performance compared with setInterval

Here we will use the same HTML as above, but the JavaScript is different.

First, add the vendor prefixes of requestAnimationFrame (thank you paulirish!):

(function() {
var browser = ['ms', 'moz', 'webkit', 'o'];
for(let x = 0, length = browser.length; x < length && !window.requestAnimationFrame; x++) {
window.requestAnimationFrame = window[browser[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[browser[x]+'CancelAnimationFrame']
|| window[browser[x]+'CancelRequestAnimationFrame'];
}
}());

Then add the eventListener for all the menu buttons:

Why we use e.preventDefault() here is that, arrow function will invoke all functions here, so if we do not set e.preventDefault(), it will trigger and scroll to all DIVs.

We can start to create our scroll function!

First, we will need to have timestamp, target position, current position and calculated position.

For target position, we used getBoundingClientRect().top, this method will get the top position in view port, when top equals 0, that means it comes to the top of the browser.

The firstPos variable is the vertical position of the browser, which is scrollY, and it has differnt name in various browsers.

pos variable is for recording the position of scroll animation.

Okay, we called window.requestAnimationFrame(showAnimation) but nothing happens, because we have not create the function!

Create our first scroll function!

First, we use the default timestamp or new Date() to get current time, this is our starting point.

Since requestAnimationFrame is using step, which mean it will create a new timestamp at each animation step, so we can know the elapsed time of animation using timestamp - start.

The progress variable is for calculating the percentage of our animation. In our example, we used 600ms as our duration of animation. Therefore, we can use elapsed / 600 to know our progress.

It’s time to scroll

The most important part is coming!

We are ready to fly!! (by Ricardo Resende on Unsplash)

In each step, we need to calculate and let browser scroll down to target position.

We have two situations here: scroll up or scroll down. If the target is under current position, we will use this formula: firstPos + (target * progess)).

For example, your target is 650px, current position is 0 pixel, which is 0 and progress is 10%, the formula becomes 0 + (650 * 10%).

Otherwise, we will use this formula to scroll up: firstPos — (firstPos * progress).

For example, you want to scroll to top, current position is 1200 pixels, and progress is 10%, the formula becomes (1200 — (1200 * 10%)).

Just add this inside the scroll function:

Just one line: window.scrollTo(0,pos). Finally, it scrolls!!

At this time, we finished our first step of animation, but it only moves few pixels, we will need to set a condition and let the animation continues.

IF-ELSE is coming to help!

For scroll down, if the position is bigger than first position plus target, it will cancel and stop animation. Otherwise, it will start a new step by calling window.requestAnimationFrame(showAnimation) again.

After calling and calling requestAnimationFrame, we can create a smooth scroll!

Hints: focus is for accessibility purposes, this will set focus to the target section, so when user scrolls down, he or she can follow links after that section.

Bonus: Ease scrolling

Yeah! We are able to DIY our smooth scroll! Wants more? You can add ease scrolling function!

It seems difficult, but it is not. Why? Because there are already lots of ready functions for ease effects. This time, we choose our ease-in function from author of Tween.js.

Just need to adjust few lines of code:

Copy the function you want from the above link, and create a new variable called easeInPercentage. This function will print results from 0 to 1, so it controls the final value of pos.

Then, just change the variable in pos from progress to easeInPercentage and try again. Wow, smooth scroll rocks!

Tested in IE 11, Edge, Chrome, Firefox and all works!

I hope all of you know the fundamentals of smooth scroll now. Welcome to leave comments or let me know if there is any improvements!

Like what you read? Give Yuki C. a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.