Andy's Net

Welcome to the smooth scroll example

This is a loooooong page...

About

As you scroll down this brief page, you'll find some links, pretty much all of these links will be anchors, these are the usual anchors you find in HTML, designed to quickly create links to specific parts of a page, however by overruling the default action of snapping to the anchor point, we can make a smooth scroll to the particular point of interest (anchor), creating a nicer and more sophisticated feel.

A look at the code

(function(){
    "use strict";
    
    /*
        Find all of the anchor links in the page and assign an on click event listener.
    */
    const allAnchors = document.querySelectorAll('a[href^="#"]');
    if (allAnchors.length > 0){
        let i = 0;
        for(; i < allAnchors.length; i++){
            allAnchors[i].addEventListener('click', scrollToId.bind(null, allAnchors[i].hash.split('#')[1], 10));
        }
    }

    /*
        This is the initial function that is called when clicking on an anchor link.
    */
    function scrollToId(id, speed, e){
        e.preventDefault();
        
        // Find the target element.
        const target = document.getElementById(id);
        
        // Check if the speed is an actual number.
        if (isNaN(speed)){
            console.error(speed, 'is not a number.');
            return false;
        }
        
        // Only run if the target element exists.
        if (target !== null){
            // Get the targets X Y location and the current windows viewpoint X Y location.
            const targetXY = [target.getBoundingClientRect().left - document.body.getBoundingClientRect().left - 5, target.getBoundingClientRect().top - document.body.getBoundingClientRect().top -2],
                  currentXY = [window.pageXOffset, window.pageYOffset];

            // Start the scrolling animation, passing the targets X Y location, the viewports X Y location and the desired speed.
            moveScroll(targetXY, currentXY, speed);
        }
    }

    /*
        Initiates the moving loop and continues to scroll until our desired destination has been reached.
    */
    function moveScroll(targetXY, currentXY, speed){
        // Get our current location and create some variables.
        const deltaXY = [Math.ceil(currentXY[0] - targetXY[0]), Math.ceil(currentXY[1] - targetXY[1])],
              newXY = [],
              // These can be changed to your desired settings, smaller numbers will increase the overall scroll duration.
              upperLimit = 640,
              lowerLimit = 3;

        /* Upper Limit
            This will limit the maximum scroll distance (upperLimit - in pixels) per animation tick, this can be used to stop very large jumps when the anchor point is far away in relation to the viewport.
        */
        if ( deltaXY[0] >= upperLimit ) deltaXY[0] = upperLimit;
        if ( deltaXY[0] <= -upperLimit ) deltaXY[0] = -upperLimit;
        if ( deltaXY[1] >= upperLimit ) deltaXY[1] = upperLimit;
        if ( deltaXY[1] <= -upperLimit ) deltaXY[1] = -upperLimit;
        
        /* Lower Limit
            This will sacrifice scrolling accuracy (lowerLimit - in pixels), but will result in the user being able to regain control of their scroll bar sooner, rather than waiting for [lowerLimit] (default of 3px) scroll movements.
        */
        if ( deltaXY[0] > 0 && deltaXY[0] < lowerLimit ) deltaXY[0] = 0;
        if ( deltaXY[0] < 0 && deltaXY[0] > -lowerLimit ) deltaXY[0] = -0;
        if ( deltaXY[1] > 0 && deltaXY[1] < lowerLimit ) deltaXY[1] = 0;
        if ( deltaXY[1] < 0 && deltaXY[1] > -lowerLimit ) deltaXY[1] = -0;
        
        // Only calculate the new scroll position if needed.
        if (deltaXY[0] < -1 || deltaXY[0] > 1){
            newXY[0] = currentXY[0] - ( deltaXY[0] / speed );
        }else{
            newXY[0] = currentXY[0];
        }
        if (deltaXY[1] < -1 || deltaXY[1] > 1){
            newXY[1] = currentXY[1] - ( deltaXY[1] / speed );
        } else {
            newXY[1] = currentXY[1];
        }

        // Actually move the scrollbar position.
        window.scrollTo(newXY[0], newXY[1]);

        // Check to see if we have reached our destination.
        if ((deltaXY[0] < -1 || deltaXY[0] > 1) || (deltaXY[1] < -1 || deltaXY[1] > 1)){
            // Set our currentXY to the newXY.
            currentXY = newXY;
            // Continue our scroll animation.
            requestAnimationFrame( moveScroll.bind(null, targetXY, currentXY, speed) );
        }
    }
}());

Some Random Definitions

Definition of Brief:

Of short duration; not lasting for long.
Concise in expression; using few words.

The Oxford English Dictionary

Definition of Nice:

Giving pleasure or satisfaction; pleasant or attractive.
(especially of a difference) slight or subtle.

The Oxford English Dictionary

Definition of sophisticated:

Having, revealing, or involving a great deal of worldly experience and knowledge of fashion and culture.
(of a machine, system, or technique) developed to a high degree of complexity.

The Oxford English Dictionary

Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis orci id mi condimentum iaculis. Vestibulum sed gravida urna. Quisque tempor ornare fringilla. Vivamus posuere mauris ligula, sed mattis est ornare in. Vestibulum suscipit nunc sit amet sem aliquet imperdiet. Nunc dignissim urna tortor, id pharetra dolor placerat ac. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nunc quis efficitur erat, sed tempus ante. Praesent egestas dapibus odio sit amet pretium.

Vivamus mattis erat magna. Nullam feugiat hendrerit nisl quis interdum. In hac habitasse platea dictumst. Aliquam bibendum erat vitae metus pharetra facilisis. Sed nec rutrum quam, eget facilisis mi. Maecenas eu molestie nisi, dapibus dignissim elit. Fusce fermentum diam dolor, ac mattis arcu bibendum nec. Nunc sollicitudin sollicitudin orci, ut aliquam ex sagittis non. Aliquam pellentesque ligula sit amet enim volutpat, vel posuere dolor dapibus.

Suspendisse potenti. Praesent finibus augue nec velit cursus porttitor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras finibus velit at justo interdum laoreet. Morbi volutpat lorem at ligula iaculis ullamcorper. Nulla nec ligula ante. Curabitur vel pretium ante. Maecenas ac enim at mauris congue condimentum et eu ex.

Vestibulum rhoncus porttitor laoreet. In auctor mi eu leo accumsan elementum. Curabitur placerat maximus molestie. Cras sed sapien egestas, placerat lectus volutpat, tincidunt felis. Nunc condimentum, velit vel viverra gravida, risus eros ultricies purus, tempus tincidunt quam lorem sed tortor. Maecenas et dignissim elit. Cras eros turpis, volutpat sed magna vel, tristique maximus tellus. Curabitur sit amet commodo orci. In hac habitasse platea dictumst. Cras fermentum ante at sapien porttitor iaculis. Maecenas condimentum sapien in vestibulum commodo.

Ut posuere vestibulum sodales. Pellentesque eu elit laoreet, convallis lorem sed, scelerisque augue. Nullam tristique eleifend libero, non finibus magna sagittis ac. Duis placerat malesuada vulputate. Phasellus ipsum tellus, luctus sed sapien eget, commodo sagittis turpis. In vitae commodo neque, vel luctus lorem. Quisque eget justo nibh. Nullam quis ante laoreet neque malesuada venenatis. Integer scelerisque placerat lobortis.

Sed pulvinar sem at nisi cursus bibendum. Phasellus id ornare mauris. Praesent ac porttitor ligula. Mauris imperdiet feugiat libero, cursus ullamcorper neque ultrices sit amet. Mauris at tempor lectus, id tempus enim. Cras elementum consequat metus vitae convallis. Donec imperdiet viverra sollicitudin. Etiam ut porta nisi. Mauris ac lorem blandit metus porttitor blandit. Maecenas non pretium orci. Donec et finibus sapien. Nulla ultrices eleifend lacus in vulputate. Duis volutpat nunc sit amet diam aliquet, eget consequat augue vulputate. Mauris suscipit, sapien eget lobortis efficitur, libero risus condimentum est, a faucibus sapien mauris non odio. Cras malesuada blandit sapien auctor hendrerit.