Smooth Scrolling with Just 1.1KB

If you are already using a JavaScript library for your animations (e.g. Velocity.js) on your project, chances are it has a function that allows you to smooth scroll within the page and possibly even within scrollable containers. So you could just use it to add smooth scrolling.

But there are cases where you find yourself working on a project that doesn’t require much JavaScript to justify using Velocity.js (34KB) (or even worse jQuery (84KB)) just to add smooth scrolling. The thing is you don’t have to because there is a very tiny JavaScript module called Zenscroll.


I came across Zenscroll recently and it quickly became my go-to scrolling module. What’s not to love:

  • Tiny: only ~2KB minified, and only 1.1KB gzipped
  • Has no dependencies
  • Awesome features
  • Good browser support

I can already hear you going “holy crap that’s awesome”, but wait there’s more!

The most convenient feature Zenscroll provides is automatic smooth-scolling on links within the same page (can be disabled). So if you literally only want to add smooth scrolling to same page links, then you literally only need to include Zenscroll in your HTML and you’re done. There’s no need to write any JavaScript yourself unless you want to change the default parameters.

Other useful features

  • Smooth animated scrolling, using the browser’s built-in smooth-behavior if it’s enabled.

  • Scroll to the top of a specific element.

  • Scrolling an element into view, making sure both top & bottom are visible, if possible.

  • Scroll to an element and center it on the screen.

  • Customize the duration of the individual scroll operations.
  • If you provide a callback function it will be executed when the scrolling is done.

  • Specify the spacing between the element and the edge of the screen (e.g., for fixed navigation bars and footers).

Visit Zenscroll’s Demo Page to learn how to use it

However, there’s one small bug I encountered whilst playing around with it.

The bug discussed below is from an old version of Zenscroll

Problem with Disabling Automatic Smoothing on Local Links

By default Zenscroll takes care of smooth scrolling on local links automatically and that’s reasonable. And you can easily change the default parameters for the automatic smoothing (and all other scrolling):

1var defaultDuration = 777; // ms
2var edgeOffset = 42; // px
3zenscroll.setup(defaultDuration, edgeOffset);

You can disable automatic scrolling all together (why would you?) or on specific links (possible scenario: adding a callback function on scroll completion).

Unfortunately, I found in some browsers when I disable automatic scrolling and add my own Zenscroll behaviour to a click event on a local link, the page jumps to the expected target (no scrolling) then jumps back to the link that was clicked before executing the desired custom Zenscroll behaviour. The problem doesn’t happen every single time, but it was certainly repeatable. This is really the only drawback I encountered with Zenscroll.

Note that this problem doesn’t occur when you use Zenscroll programmatically on elements other than local links.

Callback Function on Local Links with Zenscroll

To add a callback function on scroll completion you normally do this:, duration, onDone);
3//example, 600, function () {
5 console.log("scroll complete");

But given the problem with local links outlined above, you can use a simple workaround: keep the automatic smoothing and use setTimeOut() to execute your code on scroll completion. Why? Because you know the duration of the scroll; by default it's 999ms or you can set the default value yourself with zenscroll.setup()


You have a comment/reply link. When clicked it takes you to the comment field on the same page. And on scroll completion you want to give focus to the comment field (textarea element)

Below is a simplified example and not a fully functioning solution

1<!-- comment -->
2<a href="#commentField" class="reply">Reply</a>
3<!-- more comments -->
10 <textarea id="commentField"></textarea>
15<script src="js/zenscroll-min.js"></script>

Add eventListener to all 'Reply' links

1var replies = document.getElementsByClassName("reply");
3for (var i = 0; i < replies.length; i++) {
4 replies[i].addEventListener("click", prepareReply);

Add focus to comment field on scroll completion

1function prepareReply(e) {
2 var commentField = document.getElementsById("commentField");
3 setTimeout(function () {
4 commentField.focus();
5 }, 999);

Last Words

I’m so thankful that Gabor Lenard has released Zenscroll into the public domain. Despite the small bug with local links, it is immensely powerful for a 1.1KB module.

Now I’m just waiting for the day I enter a stackoverflow question on smooth scrolling and read “just use Zenscroll” among the answers. Because it is indeed the “One JavaScript to Smooth-Scroll Them All”.