Most all modern browsers contain the functionality to open a page at a certain anchor element on the page when loaded with a hash element in the link. For example, a link to http://www.mysite.com/#super-element would open the page and display the element with the id=”super-element” attribute. I recently had a request to load the page and gently scroll to the element after the page had fully loaded to show that there was more content on the page.

Unfortunately there is no way to override how the browser treats the hash element but we can modify the hash element to an id that does not exist on the page. For example, if we link to http://www.mysite.com/#_super-element then nothing at all would happen. With this in mind we can create an autoscrolling object that will scroll to an element on the current page or modify the outbound link to add an underscore to the hash before redirecting. This is a great solution for single page websites or sectional websites with long pages where scrolling is beneficial to the user experience.

jQuery(function($){

	$('.hash-link a').on('click', scroller.hashLinkClicked);
	scroller.loaded();
});

(function($){

	scroller = {
		topScrollOffset: -84,
		scrollTiming: 1000,
		pageLoadScrollDelay: 1000,
		hashLinkClicked: function(e){

			// current path
			var temp    = window.location.pathname.split('#');
			var curPath = scroller.addTrailingSlash(temp[0]);

			// target path
			var link       = $(this).attr('href');
			var linkArray  = link.split('#');
			var navId      = (typeof linkArray[1] !== 'undefined') ? linkArray[1] : null;
			var targetPath = scroller.addTrailingSlash(linkArray[0]);

			// scrollTo the hash id if the target is on the same page
			if (targetPath == curPath && navId) {
				e.preventDefault();
				scroller.scrollToElement('#'+navId);
				window.location.hash = scroller.generateTempNavId(navId);

			// otherwise add '_' to hash
			} else if (navId) {
				e.preventDefault();
				navId = scroller.generateTempNavId(navId);
				window.location = targetPath+'#'+navId;
			}
		},
		addTrailingSlash: function(str){
			lastChar = str.substring(str.length-1, str.length);
			if (lastChar != '/')
				str = str+'/';
			return str;
		},
		scrollToElement: function(whereTo){
			$.scrollTo(whereTo, scroller.scrollTiming, { offset: { top: scroller.topScrollOffset }, easing: 'easeInOutQuart' });
		},
		generateTempNavId: function(navId){
			return '_'+navId;
		},
		getNavIdFromHash: function(){
			var hash = window.location.hash;

			if (scroller.hashIsTempNavId()) {
				hash = hash.substring(2);
			}

			return hash;
		},
		hashIsTempNavId: function(){
			var hash = window.location.hash;

			return hash.substring(0,2) === '#_';
		},

		loaded: function(){

			if (scroller.hashIsTempNavId()) {
				setTimeout(function(){scroller.scrollToElement('#'+scroller.getNavIdFromHash());},scroller.pageLoadScrollDelay);
			}
		}
	};

})(jQuery);

This will scroll to the hash element on the current page or load a new page with an underscore in the hash element. On page load the scroller.loaded function will then scroll to the element on the current page if it exists. I am using the jQuery scrollTo plugin but you could easily replace the scroller.scrollToElement() function to look something like this for a similar effect:

scrollToElement: function(whereTo){
			$('html, body').animate({ scrollTop: $(whereTo).offset().top }, scroller.scrollTiming);
		},

4 comments on “Scroll to an Element With Anchor Id After Loading the Page Using jQuery

  1. Krzysztof PÅ‚aneta says:

    Hi there,

    Thank you for the script. It almost worked;)

    I had to change “a few” things to make it work, e.g. line 16 (from “pathname” to “href”). I prefer functional programming in JS. The code uses Vanilla JS + Velocity.js for animation + stopDef helper (from http://javascript.about.com/od/byexample/a/events-preventdefault-example.htm). You can find the whole script below.

    For simplicity I got rid of all the code for addingEventListeners for each link click so if anybody wants to use it properly they should configure them and change the first line of code.


    var hashLinks = document.querySelectorAll('.hashLink')[0],
    hash = window.location.hash;

    function smoothScroll(e){

    var targetEl = e.target;

    // make current path
    var tempPath = window.location.href.split('#'),
    curPath = addTrailingSlash(tempPath[0]),

    // make target path
    link = targetEl.getAttribute('href'),
    linkArray = link.split('#'),
    hookID = (typeof linkArray[1] !== 'undefined') ? linkArray[1] : null,
    targetPath = addTrailingSlash(linkArray[0]);

    // scroll to the hash id if the target is on the same page
    if (targetPath == curPath && hookID) {
    qqStopDef(e,false);
    scrollToElement(hookID);

    // otherwise add '_' to hash
    } else if (hookID) {
    qqStopDef(e,false);
    window.location = targetPath+'#_'+hookID;
    }
    }

    function addTrailingSlash (str){
    lastChar = str.substring(str.length-1, str.length);
    if (lastChar != '/') str = str+'/';
    return str;
    }

    function scrollToElement (hookID){
    Velocity(
    document.getElementById(hookID),
    'scroll'
    , {
    duration: 300,
    complete: function(){
    window.location.hash = '#'+hookID;
    }
    }
    );
    }

    if (hash.substring(0,2) === '#_') {
    var hookID = hash.substring(2);
    setTimeout(
    function(){
    scrollToElement(hookID);
    },
    1000
    );
    }

    1. Ludvig says:

      Hi, Im kinda new to javascript.
      Could you make this script so it animates the scroll for like a second, and also make it so that it scrolls to the element – 100px?
      Or explain to me how I can change these settings by myself?

  2. Jens says:

    Is it possible to remove the # and all after it, after performing the action?

  3. AM Webdesign says:

    @Jens: you can remove the hash with
    location.hash = “”;

Comments are closed.