30

I want to navigate to an anchor point on a new page, but I want the page to load at the top then immediately smooth scroll to the relevant anchor point. Can this be done?

I am a complete newbie with Javascript.

This is the js I currently use for smooth scrolling within the current page. I just apply a class of 'scroll' on the link.

Thanks very much!

<script>
$(function(){
  $('.scroll').on('click',function(e) {
    e.preventDefault();
    $('html, body').animate({ scrollTop: $($(this).attr('href')).offset().top + 'px' }, 1000, 'swing');
  });
});
</script>
gmo
  • 8,860
  • 3
  • 40
  • 51
Mr Toad
  • 202
  • 2
  • 12
  • 41

2 Answers2

58

As browsers automatically detect the hash and take you to that position...
It occurs to me that you could first reset the scroll position to 0 and then made the smooth scrolling.

Something like...

// to top right away
if ( window.location.hash ) scroll(0,0);
// void some browsers issue
setTimeout( function() { scroll(0,0); }, 1);

$(function() {

    // your current click function
    $('.scroll').on('click', function(e) {
        e.preventDefault();
        $('html, body').animate({
            scrollTop: $($(this).attr('href')).offset().top + 'px'
        }, 1000, 'swing');
    });

    // *only* if we have anchor on the url
    if(window.location.hash) {

        // smooth scroll to the anchor id
        $('html, body').animate({
            scrollTop: $(window.location.hash).offset().top + 'px'
        }, 1000, 'swing');
    }

});

Edit: Move the scroll(0,0)outside $(function(){...}); to prevent flickering.
Also, Snippet with working example was added.
The effect is best appreciated when viewed in full screen

        html, body {
            margin: 0;
            padding: 0;
        }
        .hidden-code {
            display: none;
            visibility: hidden;
            opacity: 0;
        }
        .header {
            background-color: #ccc;
            padding: 5px;
        }
        .header li {
            padding: 5px;
            margin: 5px;
            display: inline-block;
        }
        .articles > div {
            border: 1px solid;
            margin: 10px;
            padding: 250px 50px;
            background-color: #ccc;
        }
        div:before {
            content: attr(id);
        }
        .footer {
            text-align: center;
        }
    <div class="header">
        <ul>
            <li>page header title/navbar</li>
            <li><a class="scroll" href="#text-1">#text-1</a></li>
            <li><a class="scroll" href="#text-2">#text-2</a></li>
            <li><a class="scroll" href="#text-3">#text-3</a></li>
            <li><a class="scroll" href="#text-4">#text-4</a></li>
            <li><a class="scroll" href="#text-5">#text-5</a></li>
            <li><a class="scroll" href="#text-6">#text-6</a></li>
            <li><a class="scroll" href="#text-7">#text-7</a></li>
            <li><a class="scroll" href="#text-8">#text-8</a></li>
        </ul>
    </div>

    <div class="container">

        <div class="content">

            <div class="articles">
                <div id="text-1"></div>
                <div id="text-2"></div>
                <div id="text-3"></div>
                <div id="text-4"></div>
                <div id="text-5"></div>
                <div id="text-6"></div>
                <div id="text-7"></div>
                <div id="text-8"></div>
            </div>

        </div>

        <div class="footer">company &copy; 2015</div>

    </div>

    <div class="hidden-code">

        <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script type="text/javascript">

            // to top right away
            if ( window.location.hash ) scroll(0,0);
            // void some browsers issue
            setTimeout( function() { scroll(0,0); }, 1);

            // any position
            $(function() {
                // your current click function
                $('.scroll').on('click', function(e) {
                    e.preventDefault();
                    $('html, body').animate({
                        scrollTop: $($(this).attr('href')).offset().top + 'px'
                    }, 1000, 'swing');
                });
                // *only* if we have anchor on the url
                if(window.location.hash) {
                    // smooth scroll to the anchor id
                    $('html, body').animate({
                        scrollTop: $(window.location.hash).offset().top + 'px'
                    }, 1000, 'swing');
                }
            });
        </script>

    </div>
gmo
  • 8,860
  • 3
  • 40
  • 51
  • The scrolling works perfectly on the same page, but I still seem to get the initial flash on external links. It works the first couple of times, but eventually starts doing it. Strange - I must be doing something wrong! – Mr Toad May 18 '15 at 11:16
  • Try this code locally and tell me if you find the same problems. What OS and browser you use? http://pastebin.com/raw.php?i=3JbPp9wn – gmo May 18 '15 at 12:14
  • Hey! So sorry - I have been away. This works perfectly The previous tests were done locally on OSX Yosemite testing across multiple browsers (safari, firefox, opera and Chrome). Thanks again! – Mr Toad May 28 '15 at 01:41
  • Perfect! .. I'm glad that it has been helpful. – gmo May 28 '15 at 07:42
  • 1
    @gmo Can you please explain why are you doing scroll(0,0) two times when an anchor is present? and why don't you take the one that is timed out into account as well when checking for the hash? – Cu7l4ss Feb 28 '16 at 16:21
  • It is scrolling to the section, but again reverting back to top. What might be ta case? – Luzan Baral Jul 26 '17 at 16:41
  • @LuzanBaral Without your code, difficult to say, can you share a fiddle example?. But I presume you have another script who is scrolling to top. Try loading the page with an anchor and without this code and see if it taking you to the top. – gmo Jul 27 '17 at 07:54
  • 1
    @gmo it worked after I removed first 4 lines of your code. Thanks! – Luzan Baral Jul 31 '17 at 06:18
  • @LuzanBaral I'm glad it works for you. First four lines are useful if you load the page with an `anchor`, If `anchor is not used then yes, four first lines can be removed. – gmo Jul 31 '17 at 07:53
  • Very good! When you delete first 4 lines then it is a good solution for onepagers with lots of hidden content. – herrfischer Sep 08 '17 at 10:05
  • Had to change it to `$('html, body').delay(2000).animate({ scrollTop: $(window.location.hash).offset().top + 'px' },'slow');` before it worked for me. – Matt May 30 '19 at 12:07
  • This thread hasn't been active in a while - but does anyone know how to amend the code so that the # is removed from the url when navigating from another page? – Mr Toad Sep 28 '19 at 09:26
  • @MrToad, It is not related to OP, who wants to scroll based on an `anchor` extracted from the `hash` in the URL. Do you maybe want to [remove the hash from the url](https://stackoverflow.com/search?q=remove+hash+from+url)? – gmo Oct 02 '19 at 11:00
  • @gmo lovely bro! I am about to implement this, but wanted to know is there a way to add some sort of padding to the scroll when it reaches the anchor? Currently it scrolls to the anchor and it's right at the top of the browser. Can this be done such that it scrolls to the centre of the browser and highlighted briefly? – Jay Smoke Apr 30 '21 at 13:11
  • 1
    @JaySmoke sure, just sum any pixels you want to```scrollTop``` function, like ie. 150 -> ```...offset().top + 150 + 'px'``` – gmo Apr 30 '21 at 17:28
  • @JaySmoke for highlight, you could use a callback function on ```complete``` see doc. -> https://api.jquery.com/animate/ – gmo Apr 30 '21 at 17:30
0

Here's a more modern method that seems to work very well. This must be placed outside of any document.ready or window.onLoad handler.

// Handle page load
if ( window.location.hash ) {
    var target = window.location.hash.slice( 1 );
    if ( document.getElementById( target ) ) {
        $( function() {
            if ( window.location.hash ) {
                if ( $( '#' + target ).length ) {
                    window.scrollTo( 0, 0 );
                    $( 'html, body' ).animate( {
                        scrollTop: $( '#' + target ).offset().top - 50
                    }, 800 );
                }
            }
        } );
        if ( 'scrollRestoration' in history ) {
            history.scrollRestoration = 'manual';
        }
        window.scrollTo( 0, 0 );
    }
}

// Handle anchor links
$( function() {
    $( 'a[href^="#"]' ).on( 'click', function( e ) {
        e.preventDefault();
        $( 'html, body' ).animate( {
            scrollTop: $( $.attr( this, 'href' ) ).offset().top - 80
        }, 800 );
        return false;
    } );
} );
Gavin
  • 7,544
  • 4
  • 52
  • 72