Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Set Offsett for Smooth Scroll

I have implemented the CSS Tricks Smooth Page Scroll on my site and it's working pretty nicely. However, because I have a fixed nav at the top of the page, when the page scrolls to the appropriate anchor div, the top of the div disappears behind the nav. How can I offset the scroll (about 70px) so that the whole div is shown? I tried doing this:

var targetOffset = $target.offset().top - 70;

But that doesn't quite work. The page scrolls to the appropriate spot but then it immediately jumps back up so that the top of the div is hidden. What am I missing? Here's the code in full:

$(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');

    // Any links with hash tags in them (can't do ^= because of fully qualified URL potential)
    $('a[href*=#]').each(function() {

        // Ensure it's a same-page link
        var thisPath = filterPath(this.pathname) || locationPath;
        if (  locationPath == thisPath
            && (location.hostname == this.hostname || !this.hostname)
            && this.hash.replace(/#/,'') ) {

                // Ensure target exists
                var $target = $(this.hash), target = this.hash;
                if (target) {

                    // Find location of target
                    var targetOffset = $target.offset().top - 70;
                    $(this).click(function(event) {

                        // Prevent jump-down
                        event.preventDefault();

                        // Animate to target
                        $(scrollElem).animate({scrollTop: targetOffset}, 400, function() {

                            // Set hash in URL after animation successful
                            location.hash = target;

                        });
                    });
                }
        }

    });


    // Use the first element that is "scrollable"  (cross-browser fix?)
    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 [];
    }

});

Thanks in advance for your help.

like image 905
mcography Avatar asked Nov 08 '12 17:11

mcography


People also ask

What is scroll offset?

forward, then scroll offset is the amount the top of the sliver has been scrolled past the top of the viewport. This value is typically used to compute whether this sliver should still protrude into the viewport via SliverGeometry.

How do I create a smooth scrolling anchor link?

You can use window. scroll() with behavior: smooth and top set to the anchor tag's offset top which ensures that the anchor tag will be at the top of the viewport.


3 Answers

This always happens. I search and search for an answer, get frustrated, post a question asking for help, and then immediately find an answer to my problem. Silly. Anyway, here's the solution for anyone who might be having the same problem.

If you want to change the offset by 70px, for example, change the code to this:

var targetOffset = $target.offset().top - 70;

However, unless you remove this line from the code...

location.hash = target;

... the page will scroll to the right spot and then immediately jump back up so that the top of the div is hidden behind the header. You can remove the above line from the code and everything will work great, except for the fact that the URL will no longer change to reflect the user's position on the page.

If you want the URL to change (and I think this is a good idea for usability purposes), then all you have to do is change the CSS for the anchor divs. Add a positive value for padding-top and a negative value for margin-top. For example:

#anchor-name {
padding-top: 70px;
margin-top: -70px;
}

I only have 3 divs, so I just plugged in that CSS to each of them and voila, everything worked. However, if you have a lot of anchor divs, you might consider creating a class of .anchor, putting the CSS there, and applying the class to all the appropriate divs.

I hope this helps!

like image 55
mcography Avatar answered Oct 05 '22 14:10

mcography


I have fixed such a kind of issue with below code:

Working demo HERE. You can play with "Post Topics" section in the sidebar and content in the main-content area.

Code

jQuery(function() {
  jQuery('a[href*=#]:not([href=#])').click(function() {
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {

      var target = jQuery(this.hash);
      target = target.length ? target : jQuery('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        jQuery('html,body').animate({
          scrollTop: target.offset().top -100
        }, 1000);
        return false;
      }
    }
  });
});
like image 45
Kushal J. Avatar answered Oct 05 '22 12:10

Kushal J.


Refer to https://codepen.io/pikeshmn/pen/mMxEdZ

Approach: We get the height of fixed nav using document.getElementById('header').offsetHeight And offset the scroll to this value.

var jump=function(e){  

e.preventDefault();                        //prevent "hard" jump
  var target = $(this).attr("href");       //get the target

      //perform animated scrolling
      $('html,body').animate(
        {
          scrollTop: $(target).offset().top - document.getElementById('header').offsetHeight - 5  //get top-position of target-element and set it as scroll target
        },1000,function()                  //scrolldelay: 1 seconds
        {
          location.hash = target;          //attach the hash (#jumptarget) to the pageurl
        });
      }

  $(document).ready(function()
  {
    $('a[href*="#"]').bind("click", jump); //get all hrefs
    return false;
  });
like image 45
Pikesh Prasoon Avatar answered Oct 05 '22 12:10

Pikesh Prasoon