I was working on a site today that had several links in which the href attribute references an id or hash value on another page. The site has a fixed header, so I needed to way to offset the element referenced in the URL’s hash from the top of the page. Otherwise, some content would be hidden behind the fixed header.

Solutions for this problem with in-page links have been thoroughly documented across the Web (mine is included at the bottom of this post). However, in the case of links that are not in-page, I found Uncle Google (ahem, StackOverlflow) to be lacking. My problem is with links that take the user to a new page. Specifically, I have a call to action whose href links to a contact page and includes the hash value of a form id on that page. The URL looks something like this:

<a href="https://domain.com/contact#form">Contact Us</a>

When a user clicks the “Contact Us” link and the contact page loads, I need a way to grab the hash value from the URL that corresponds with the form element’s id and adjust the top offset accordingly. Otherwise, some form fields will be hidden behind the fixed header. This seems like something that would have been done 1,000 times over… Apparently not, at least judging by Google’s search results.

I spun my wheels for a bit trying to figure out an elegant way to solve the problem. Typically, I prefer to rely more on CSS than JavaScript for UI issues like this. What I came up with accomplishes that goal. My solution uses minimal JavaScript for DOM manipulation and relies on CSS to do the visual lifting.

Below, the solution to my fixed header dilemma is provided in in two flavors: jQuery and vanilla JavaScript. FWIW, even though the site I am working on uses jQuery, I opted for the vanilla JavaScript solution.

Fixed Header jQuery Solution

Link to an element on another page and account for a fixed header offset using jQuery.

if ( window.location.hash ) {
    var hash = window.location.hash,
        $hash = $(hash);

    $hash.before('<div id="'+hash.slice(1)+'" class="hashlink"></div>');
    window.location.hash = hash;

Fixed Header [vanilla] JavaScript Solution

Link to an element on another page and account for a fixed header offset using vanilla JavaScript.

if ( window.location.hash ) {
    var hash = window.location.hash,
        id   = hash.slice(1),
        elem = document.getElementById(id),
        hashlink = '<div id='+id+' class="hashlink"></div>';

    elem.insertAdjacentHTML('beforebegin', hashlink);
    window.location.hash = hash;

In both examples you can see that I first check if the URL contains a hash value on line 1. Following that, variables are created to store the hash value, as well as the html that needs to be added. The critical thing to understand is on line 6 of the jQuery example and line 8 of the vanilla JavaScript example, where a new element is added to the DOM.

The line that immediately follows the DOM insertion in both examples updates the window.location.hash value with the new element’s id (which retains the same value of the hash that was originally linked to). This forces the browser to jump to the new element, on which we have a hashlink class that can be styled with CSS. My styles for that class look like this:

.hashlink {
    height: $header-height;
    margin-top: -$header-height;
    visibility: hidden;

Because I am handling UI updates with CSS (Sass in this case), I can reference the variable that holds the height value of my fixed header. Should I need to, I can also account for style changes in media queries. Huge win.

In-Page Link Scrolling Animation

Below is how I handle in-page links with JavaScript scrolling animations. The commented out lines are for sites that use Velocity.js, a high-performance JavaScript animation library.

// In-Page Scroll Animation
// ------------------------
$('a[href^="#"]').on('click', function(e) {
    var hash  = this.hash,
    	$hash = $(hash),
        addHash = function() {
            window.location.hash = hash;

    if ( hash !== '#header' ) {
        // $hash.velocity('scroll', { duration: 500, offset: -50, complete: addHash }); // Velocity.js
        $('html,body').animate({ 'scrollTop': $hash.offset().top -50 }, 500, addHash);
    } else {
        // $hash.velocity('scroll', { duration: 500, offset: 0, complete: addHash }); // Velocity.js
        $('html,body').animate({ 'scrollTop': $hash.offset().top }, 500, addHash);
Posted by: John Dugan