Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery script smooth scroll to different sections with a different offset

I am using a smooth scroll script for my one page site. It scrolls to each anchor.

Due to the design, I can't have the anchor snap straight to the top of the page. I have had to create hidden anchors that are further up the page so it does not snap exactly to the top.

Here is the script I am currently using:

jQuery(document).ready(function($) {
    $(".scroll").click(function(event){ 
        event.preventDefault();
        $('html,body').animate({
            scrollTop: $('[name="' + this.hash.substring(1) + '"]').offset().top
        }, 500);
    });
});

I have been informed that I can make the offset happen within this script. Rather than having these little hidden anchors everywhere, I can simply add something to the end of top to offset it by a certain number of pixels. It would be top - 250

$('html,body').animate({
    scrollTop:$('[name="' + this.hash.substring(1) + '"]').offset().top - 250
}, 500);

The problem is this would make the offset always be 250px, I need it to be variable so that for example, the portfolio div can be anchored with an offset of 200px, but the contact div only by 50px.

Can anyone help me write some sort of selector into the script that will allow me to adjust this top - [variable] based on which div is being anchored?

like image 232
Francesca Avatar asked Aug 09 '12 09:08

Francesca


2 Answers

You're not really giving an indication on what the rules are for determining the offset of the named anchor's top value.

So perhaps the easiest thing would be to introduce an attribute which you can use to adjust the offset on your named anchor or whatever element you are looking to scroll into view.

So for example here's a named anchor with a new attribute called data-section-offset and I want to offset by 20px.

<a id="myAnchor" data-section-offset="20">My Section</a>

In your click handler you can pull out the attributes value for the animation.

jQuery(document).ready(function($) {

    $(".scroll").click(function(event) {
        event.preventDefault();        
        var $anchor = $('#' + this.hash.substring(1));
        $('html,body').animate({ 
            scrollTop: $anchor.offset().top - $anchor.attr('data-section-offset')
        }, 500);        
    });
});

Here's a fiddle to show further example.

Note: JQuery has the data method so the attribute could be pulled either like this (as above)

$anchor.attr('data-section-offset')

or like this

$anchor.data('section-offset')

As @Ben pointed out HTML5 specification for custom data attributes is quite useful > HTML 5 data- Attributes.

like image 175
Chris Moutray Avatar answered Sep 30 '22 19:09

Chris Moutray


First of all, you do not need to use the old <a name= convention. Check out the w3schools page on anchors HTML anchors on w3schools. Best practice is now to link the a container element by id.

So if you are linking to a div with some content, use <div id="linkToMe">My content in here.</div> and <a href="#linkToMe">The link text</a>.

This will of course break your above code as it is looking for elements by name. You want to look for them by id (faster anyway!).

In my webpage I have a toolbar at the top which is sometimes position: fixed; so when I scroll I want to offset the scroll position so it doesn't go underneath my toolbar at the top of the page.

This is how I do it:

function goToByScroll(id) {
    //Find toolbar height
    var pageOffset = 0,
        hdr = $('#sub'),
        tb = $('#sitemenu');
    if (hdr.css('position') == 'fixed') { pageOffset += hdr.height() }
    if (tb.css('position') == 'fixed') { pageOffset += tb.height() }

    //Scroll the document
    $('html,body').animate({ scrollTop: $("#" + id).offset().top - pageOffset }, 'slow'); }

and then wire it up with jQuery:

$(".jumptoid").click(function (e) {
    e.preventDefault();

    // Track in google analytics if you are using it.
    _gaq.push(['_trackEvent', 'Jump to Id', e.currentTarget.host, this.href, 0]);

    // Scroll to item location using jquery
    goToByScroll(this.href.split('#')[1]);

    // Push History in browser bar so the forward/back button works
    window.location.hash = this.href.split('#')[1];

    return false;
});

This will perfectly align the top of the target element with the bottom of my header/toolbar if they are position fixed or the top of the browser viewport if not.

In your case you'll either want to change how you calculate the offset (instead of my hdr and tb items, you could do some other math or look at other page elements) or you can use the custom attribute as suggested by @chris moutray.

If you want to use an attribute, use the proposed html5 standard of starting with data- so that it passes validation. For exmaple <div id="linkToMe" data-scroll-offset="250">My content here</div> and then use @chris's code to grab that attribute like $anchor.attr('data-scroll-offset').

like image 27
BenSwayne Avatar answered Sep 30 '22 17:09

BenSwayne