Search code examples
javascriptjquerysmooth-scrolling

Smooth scrolling function including page change


I'm trying to write a smooth scrolling function that can handle if the href needs to load a new page first then run the scroll.

I have seen a few options where adding /page-template.html#anchor to the href, but with a dynamic site where the homepage url would just be /#anchor.

So the below code isn't seeing the slash as a part of the target href.

const $anchor = $('a')

$anchor.on('click', function(event) {

    if (this.hash !== "") {
      event.preventDefault()
      let hash = this.hash

      $('html, body').animate({
        scrollTop: $(hash).offset().top
      }, 800, function(){
        window.location.hash = hash
      })
    }
})

Solution

  • Kind of worked out a way to achieve this, but it's not tremendously pretty. Any advice on improving it would be appreciated.

    // If loading a page with a hash in the URL, scroll to it
    if (window.location.hash) {
        setTimeout(function() {
            $('html, body').scrollTop(0)
            $('html, body').animate({
                scrollTop: $(window.location.hash).offset().top
                }, 1000)
        }, 0)
    }
    
    // Get the current url path
    const currUrl = window.location.pathname
    
    $anchor.on('click', function(e) {
    
        // Get the href and a hash into variables
        const href = $(this).attr('href')
        const hash = this.hash
    
        // If a hash is present
        if (hash) {
    
            // Check if there is a URl path before the hash
            if (href.charAt(0) !== '#') {
    
                // Check if this URL path matches the current page's href
                if (currUrl == href.split('#')[0]) {
                    e.preventDefault()
    
                    // As they match, just run the scroll within the same page
                    $('html, body').animate({
                        scrollTop: $(hash).offset().top
                    }, 800, function() {
                        window.location.hash = hash
                    })
                }
    
            // There is no URL accompanying the hash, so it's got to be within the same page
            } else {
                e.preventDefault()
                // Run smooth scrolling within the page
                $('html, body').animate({
                    scrollTop: $(hash).offset().top
                }, 800, function() {
                    window.location.hash = hash
                })
            }
        }
    })