37

I am using the following code to scroll to anchor points with jQuery:

$(document).ready(function() {
  function filterPath(string) {
  return string
    .replace(/^\//,'')
    .replace(/(index|default).[a-zA-Z]{3,4}$/,'')
    .replace(/\/$/,'');
  }
  var locationPath = filterPath(location.pathname);
  var scrollElem = scrollableElement('html', 'body');

  $('a[href*=#]').each(function() {
    var thisPath = filterPath(this.pathname) || locationPath;
    if (  locationPath == thisPath
    && (location.hostname == this.hostname || !this.hostname)
    && this.hash.replace(/#/,'') ) {
      var $target = $(this.hash), target = this.hash;
      if (target) {
        var targetOffset = $target.offset().top;
        $(this).click(function(event) {
          event.preventDefault();
          $(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
            location.hash = target;
          });
        });
      }
    }
  });

  // use the first element that is "scrollable"
  function scrollableElement(els) {
    for (var i = 0, argLength = arguments.length; i <argLength; i++) {
      var el = arguments[i],
          $scrollElement = $(el);
      if ($scrollElement.scrollTop()> 0) {
        return el;
      } else {
        $scrollElement.scrollTop(1);
        var isScrollable = $scrollElement.scrollTop()> 0;
        $scrollElement.scrollTop(0);
        if (isScrollable) {
          return el;
        }
      }
    }
    return [];
  }

});

Is there anyway to make it scroll to that anchor but minus a set amount of pixels? (in my case i want it to go -92px)

Thanks for any help.

John
  • 989
  • 2
  • 16
  • 29
  • Similar to http://stackoverflow.com/questions/832860/how-to-scroll-the-window-using-jquery-scrollto-function – robbrit Jul 06 '12 at 15:25
  • 1
    How are they similar?? Mine is to scroll to EVERY anchor via jquery, what you linked to wants to scroll when they are near the top of the page. Code is very different. – John Jul 06 '12 at 15:31
  • Only difference is to which selector you want to scroll to, and the offset. Look at the accepted answer and replace `#id` with the selector you want, and replace `100` with the offset you want. – robbrit Jul 06 '12 at 15:58

10 Answers10

38

I just had to solve this problem myself. You need to adjust your offset by the amount of pixels you want to scrollTo. In my case, I needed it to be 50 pixels higher on the page. So, I subtracted 50 from targetOffset.

Now, the part of the code that's throwing a wobbly for you is location.hash - this is telling the browser to set its location to a specific point. In all cases, this is a string containing the ID you just scrolled to. So, it'd be something like '#foo'. You need to maintain this, so we'll leave it.

However, to prevent the browser from 'jumping' when location.hash is set (a default browser action), you simply need to prevent the default action. So, pass your event 'e' through the completion function in the animate function. Then simply call e.preventDefault(). You'll have to make sure that the browser is actually calling an event, otherwise it will error out. So, an if-test fixes that.

Done. Here's the revised code chunk:

if (target) {
    var targetOffset = $target.offset().top - 50;
    $(this).click(function(event) {
      if(event != 'undefined') {
          event.preventDefault();}
      $(scrollElem).animate({scrollTop: targetOffset}, 400, function(e) {
          e.preventDefault();
          location.hash = target;
      });
    });
  }
Jonathan Savage
  • 381
  • 3
  • 4
  • Sorry, I know this is an old question but: the animate callback doesn't receive any parameters (see http://api.jquery.com/animate/), so e.preventDefault() fails. Did this change in the last 2 years? Is there an up-to-date way to prevent the default behavior of location.hash = target ? – Andreyu Jun 18 '14 at 13:38
  • Andreyu, take a look to Borgar answer in http://stackoverflow.com/questions/1489624/modifying-document-location-hash-without-page-scrolling – cfillol Nov 04 '15 at 17:11
22

This is what I use:

function scrollToDiv(element){
    element = element.replace("link", "");
    $('html,body').unbind().animate({scrollTop: $(element).offset().top-50},'slow');
};

...where 50 is the number of pixels to add/subtract.

kaleazy
  • 5,922
  • 2
  • 47
  • 51
16

This code work for me in any link anchor in my site respect "150px" height for fix menu on top.

<!-- SMOOTH SCROLL -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(function() {
  $('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        $('html,body').animate({
          scrollTop: target.offset().top-150
        }, 1000);
        return false;
      }
    }
  });
});
</script>
<!-- End of SMOOTH SCROLL -->
Max
  • 526
  • 6
  • 12
8

<span class="anchor" id="section1"></span>
<div class="section"></div>

<span class="anchor" id="section2"></span>
<div class="section"></div>

<span class="anchor" id="section3"></span>
<div class="section"></div>

<style>
.anchor{
  display: block;
  height: 115px; /*same height as header*/
  margin-top: -115px; /*same height as header*/
  visibility: hidden;
}
</style>
AndrewL64
  • 15,794
  • 8
  • 47
  • 79
  • This works great but you have to know that it might cover links, buttons or any other interactive elements that you have in the 115px above the anchor and you won't be able to click on them... – phoenix Sep 22 '15 at 21:21
1

I was unable to use Jonathan Savage's solution as I couldn't pass an event callback into animate() without error. I had this issue today and found a simple solution:

      var $target = $(this.hash), target = this.hash;
      if (target) {
        var targetOffset = $target.offset().top - 92;
        $(this).click(function(event) {
          event.preventDefault();
          $(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
            location.hash = targetOffset;
          });
        });

Subtract your pixel offset from the targetOffset variable, then assign location.hash to that variable. Stops the page jumping when scrolling to the target hash.

vibrationbaby
  • 171
  • 1
  • 8
1

This is a jQuery snippet i use and find very resourceful & flexible. You can remove the DOM Ready if you run it in the footer which is suggested. Just load any post 1.4v library ahead of it. It listens for all clicks on anchors, then it runs a boolean and an OR for class checks. If it finds a class then it runs through the script and animation. You can adjust your offset from its ending position i prefer 60px on most applications but feel free to adjust as need be.

<!--jQuerySmoothScroll-->
<script>
jQuery(document).ready(function(){
   // Add smooth scrolling to all links
   jQuery("a").on('click', function(event) {
      //check that we have the smooth-scroll class add as many as need be
            if (jQuery(this).hasClass("whatever-class-you-want") || jQuery(this).hasClass("smooth-scroll")) {
       // Make sure this.hash has a value before overriding default behavior
         if (this.hash !== "") {
           // Prevent default anchor click behavior
          event.preventDefault();
         // Store hash
         var hash = this.hash;
        // Using jQuery's animate() method to add smooth page scroll
        // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
        jQuery('html, body').animate({
        scrollTop: jQuery(hash).offset().top-60// Set offset from top position
       }, 800, function(){
   
        // Add hash (#) to URL when done scrolling (default click behavior)
        window.location.hash = hash;
      });
     } // End if
    } // End if (class)
  });
});
</script>
Garrick Crouch
  • 309
  • 4
  • 11
0

This is a jQuery implementation which I use that was based on Никита Андрейчук's solution. The pixel adjustment variable can be set dynamically this way, though it is hard coded in this example.

$( 'a' ).each(function() {
    var pixels = 145;
    var name = $( this ).attr( 'name' );
    if ( typeof name != 'undefined' ) {
        $( this ).css({
          'display'    : 'block',
          'height'     : pixels + 'px',
          'margin-top' : '-' + pixels + 'px',
          'visibility' : 'hidden'
        });
    }
});
0

Here is what i use. Set the offset to what you need.

$('a[href^="#"]').click(function(e) {
  e.preventDefault();
  $(window).stop(true).scrollTo(this.hash {duration:1000,interrupt:true,offset: -50});
});
cdrck
  • 33
  • 7
0

We can also do this with css:

scroll-padding: 92px;
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
mr._hayatt
  • 41
  • 4
-1

Not wanting to learn Javascript and always looking for the easiest option, just create an empty DIV above the anchor point you want to land at then in CSS make the div

anchorpointl{margin-top: -115px;}

or however far above or below you want to go and the jobs done

Community
  • 1
  • 1
nick
  • 9