Smooth scrolling to anchor on different page

Posted on July 26th, 2015

demo-003pic

In this quick jQuery tutorial I’ll show you how to smooth scroll to an anchor after its link was pressed on a different page. Using jQuery this is quite straightforward

 

This is a feature I implemented on this very site. If you click on ‘About Me’ or ‘Contact Me’ on the above navbar, it will link to the top of my home page and then scroll (after an intentional brief pause as logo spins) to the respective section

PREREQUISITES

  • To get me start I used a simple template from one of my previous tutorials on ‘Full background images with responsive centred elements‘. Follow that tutorial if you need elucidation on the HTML/CSS setup of the page I used to smooth scroll
  • You’ll need both jQuery and jQuery UI for this to work. Copy and Paste into header:
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>

SETUP

We are going to create two webpages: The first will be the main scrollable page with full screen background images (main.html). The second (links.html) will just consist of five buttons which are linked to the various sections on the scrollable page.

SCROLLABLE PAGE (main.html)

When designing the scrollable page, include different id tags to the various sections you want to smooth scroll to. I did so in the form of the ids section-1, section-2, section-3 and so on

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

When the webpages URL includes the id of any of the sections, it will load the page having navigated to the location of the id. We want to counter this by moving the window to the top before the page fully loads then create a function which then smooth scrolls to designated anchor. Place this script within your pages <head> tags:

$('html').css({display: 'none'});

$(document).ready(function(){
    var hashURL = location.hash;
    if(hashURL != "" && hashURL.length > 1){
        $(window).scrollTop(0);
        $('html').css({display: 'block'});
        smoothScrollTo(hashURL);
    } else {
        $('html').css({display: 'block'});
    }
});

$('html').css({display: 'none'}) hides the html page before it fully loads by setting the CSS display property to none. $(document).ready(function(){...}) waits for entire webpage to load (DOM, images, videos etc.) before running enclosed code. The variable hashURL stores the anchor part (if there is any) of a url by using location.hash property. We then check if the hashURL contains an anchor. If hashURL fails boolean test (is empty or has length of 1 meaning no anchor/link set in URL) the code in the else statement simply displays the html page. If the URL contains a link we move the webpage back to the top by setting scrollTop to 0, afterwhich we display the html page and call the smoothScrollTo() function to scroll to designated element:

function smoothScrollTo(anchor) {
    var duration= 5000; //time (milliseconds) it takes to reach anchor point
    var targetY = $(anchor).offset().top;
    $("html, body").animate({
        "scrollTop" : targetY
    }, duration, 'easeInOutCubic');
}

The crux of the function is the animation done on scrollTop(). scrollTop can set the viewports vertical position (in pixels) if its given a integer value. By placing it in the .animate() method we ensure it vertically animates/scrolls a certain amount of pixels (value given by targetY variable). targetY is retrieved by getting the given anchor element’s current coordinates (.offset()) and by calling top we extract the y-coordinate from these coordinates. As the doc states, the .animate() function can take 4 parameters, we will only use an additional 2; duration (how long the animation should take) and easing (the speed at which the animation progresses at different points within the animation). The reason for us downloading the jQuery UI suite was to broaden our repertoire of easing functions. Here I used the ‘easeInOutCubic’ function to create a nice easing effect. You may ask why we animate both the html and body elements in the smoothScrollTo() function. This is because we need to scroll on the webpages root element and different browsers set different elements as the root element. Chrome and Safari make <body> the root, whilst Firefox and IE make <html> the root. So we select both $(‘html, body’) for cross browser compatibility

LINKS PAGE (links.html)

This page is pretty straightforward. Just create 5 links which are linked to the different sections on the scrollable page:

<head>
<style type="text/css">
    body {
        margin: 20px auto;
        text-align: center;
    }
    a {
        position:relative;
        margin: 20px auto;
        font-family: 'Sans-serif', 'Palatino Linotype';
        font-size: 1.2em;
        text-decoration:none;
        color: white;
        padding: 10px;
        height: 20%;
        width: 40%;
        border-radius: 10px;
        background-color: #081b36 !important;
        display: block;
    }
    a:hover {
        background-color: #0f3162 !important;
    }
</style>
</head>
<body>
    <a href="main.html#section-1">Go to SECTION-1</a>
    <a href="main.html#section-2">Go to SECTION-2</a>
    <a href="main.html#section-3">Go to SECTION-3</a>
    <a href="main.html#section-4">Go to SECTION-4</a>
    <a href="main.html#section-5">Go to SECTION-5</a>
</body>

NAVBAR ADDON

At this point we’ve fully implemented the smooth scroll feature. As a small extension I also included a navbar on the page. All the buttons link to a specific location on the page:

<nav>
    <a href="#section-1" class="same-page-scroll">Section 1</a>
    <a href="#section-2" class="same-page-scroll">Section 2</a>
    <a href="#section-3" class="same-page-scroll">Section 3</a>
    <a href="#section-4" class="same-page-scroll">Section 4</a>
    <a href="#section-5" class="same-page-scroll">Section 5</a>
</nav>

and the CSS:

nav {
    position: fixed;
    z-index: 100;
    width: 100%;
    background-color: #76101e;
    text-align: left;
    font-family: Ubuntu, 'Sans-Serif', Times, Arial;
    font-size: 1.2em;
    padding: 15px;
    border-bottom: 5px solid #580c17;
}
nav a {
    padding: 15px 15px 15px 15px;
    text-decoration: none;
    color: #fdeef0;
}
nav a:hover {
    background-color: #580c17;
}

To make each navbar link smooth scroll down to specified location just add this code just before closing your <body>:

<script type="text/javascript">
    $('a[href^="#"]').bind('click', function(event){
        var anchor = $(this).attr('href');
        smoothScrollTo(anchor);
        return false;
    });
</script>

a[href^="#"] is a CSS selector which selects every <a> element whose href attribute value begins with “#” (an anchor/ link). .bind() overrides a specific event for an element (in this case the ‘click’ event) with your custom code. So when we click on any <a> element on the page with an anchor as the href, we retrieve this anchor by calling $(this).attr('href'), then use the smoothScrollTo() function to smooth scroll to anchor point. To ensure the click events default actions are not called, return false.

To get a better sense of how this all comes together view complete code on Github

  • adjMedia

    in this example, how would i offset -100px?

    • Hi mate. What effect you aiming for? -100px horizontally or vertically?
      Depending on what effect you’re going for you could just simply apply -100px to one of the margin sides (e.g. margin-top: -100px;)
      Need more info in exactly what you’re trying to do to really help you out thgh…

  • Hey many thanks for the tutorial. Can you tell me why do you need jQuery UI library? Can’t be done only with jQuery? (jQuery UI is quite big)

    • Yh I admit jQuery UI is a bit of a overkill…especially since I’m only including it to just have access to more easing functions than linear and swing (the two that come as standard with jQuery)
      You can extend jQuerys easing functions manually though. All you have to do is paste this piece of code just after you load jQuery. That way you’ll have all the additional easings without the jQuery UI bloat

      • Thanks that’s really helpful. Also I liked the way you explain bit by bit what you’re doing.

        • Thanks. After a bit of a long hiatus I’ll resume making tutorials again. Just need to finish a few things

  • Henrique Baldy

    Many, many thanks for ths. Just need a little bit of hacking…
    How remove anchor link after scrolling?

    Thank you so much to anyone who can help with this.
    Cheers!

    • Not sure what’s the purpose of removing anchor link after its scrolled. After scroll anchor link effects nothing else really. What effect are you going for?

      • Henrique Baldy

        The purpose is that I’m building a one-page content which is accessed through menu.
        Please, see my mockup: http://www.meiamaratonadecascais.pt/draft/mockup-2016/?ln=en

        If you open “Event Info” and select any sub item you’ll go to the one-page with several sections of info. For instance, if you select “How to get there” it scrolls to the correct position, but if the user selects another section in the “Event Info” the scroll performs but the link still shows the previous accessed section. This can confuse some users, so I thought it would be better remove the #anchor from url.

        Thanks, Tatenda, for your kind reply.

        • Oh I see what you mean. Try adding this line at the beginning of the smoothScrollTo() function:
          location.hash = “”;This will basically replace the hash with a empty string. So before it scrolls down it will delete the hash from the url. Thats one fix I guess, hopefully that’ll suffice.
          By the way nice mockup! Really eye catching design

          • Henrique Baldy

            Thank you so much, Tatenda! It’s working!
            It would be perfect if it clears the # too, but for now it works as expected and I’m deeply thankful for your help.
            Thanks for the appreciation about the mockup 😉

            Peace from Portugal!

  • Havilah

    Thanks for this tutorial. Much better than most I have found. I used a variation of this tutorial and on the page I’m supposed to jump from, I’m still using the same nav – because it’s a wordpress project.

  • aeliayousaf

    What if i wanted to create a “back to top” when the user has scrolled to the bottom of page? how would i modify the code?
    thanks.

    • You’ll have to modify the smoothScrollTo function a bit. All you need is the latter of it.
      Create the button at the bottom of the page then add a click event listener to it to scroll to top like so:

      $("button").on('click', function() {
      $("html, body").animate({
      "scrollTop": 0
      }, 1000, 'easeInOutCubic')
      });

      • aeliayousaf

        awesome! thanks for the quick reply!

  • Lombe Chileshe

    I just want to say thank you so much for this. Helped me out a lot.