简体   繁体   中英

JQuery Smooth Scroll to Anchor with Sticky Navigation Bar

I have a webpage with a sticky header that I'm attempting to implement smooth scrolling to anchor tags for navigation. When I click on the navigation link to the section I want to go scrollTop: href.offset().top - 100 does not appear to work correctly. If I click the link again after the webpage has navigated to that section, I can see the page scroll, but then it bounces back to the top. Any idea what is going on? I'm using Microsoft Edge (Yeah, I know ...).

HTML

<!DOCTYPE HTML>
<html lang="en">
<head></head>
<body id="home">
    <nav><a href="#section1">Section #1</a></nav>
    <main>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
        <h2 id="section1">section1</h2>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
    </main>
</body>
</html>

CSS

nav {
    position:fixed;
    padding:4px;
border:2px solid #000;
width:100%;
    line-height:2.25em;
    background-color:yellow;
}

h2 {
    padding:4px;
    border:1px solid #000;
    width:100%;
    line-height:100px;
    background-color:red;
    }

jQuery

$(document).ready(function() {

    $('a[href*="#"]').click(function(event) {

        var href = $(this.hash);

        if (href.length) {
            event.preventDefault();
            $('html, body').animate({
                scrollTop: href.offset().top - 100
            }, 750, function() {
                location.hash = href.attr('id');
            });     
        }
    });
});

JSFiddle

EDIT:

I understand that setting a <div> element to display:fixed removes it from the flow of the page, which is what I believe is causing the issues. Is there a work around for this?

EDIT:

Edge and Firefox were not cooperating with initial approach to modify hashchange behavior, so this edit simply removes the window.location.hash step to prevent the jump after the animation. However, this is not ideal because it prevents the default hash location behavior.

 $(document).ready(function() { $('a[href*="#"]').on('click', function(event) { let hash = this.hash; if (hash) { event.preventDefault(); $('html, body').animate({scrollTop: $(hash).offset().top - 100}, 750); } }); }); 
 nav { position: fixed; padding: 4px; border: 2px solid #000; width: 100%; line-height: 2.25em; background-color: yellow; } h2 { padding: 4px; border: 1px solid #000; width: 100%; line-height: 100px; background-color: red; } 
 <!DOCTYPE HTML> <html lang="en"> <head></head> <body id="home"> <!-- Navigation --> <nav><a href="#section1">Section #1</a></nav> <!-- Main Content --> <main> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <h2 id="section1">section1</h2> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> <br> </main> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> </body> </html> 

ORIGINAL:

I think location.hash causes the scroll to jump to the top after the scrollTop animation has completed. You can modify the hashchange event to stop the scroll at the same distance above your anchors to eliminate the jump.

$(document).ready(function() {

  $(window).on('hashchange', function() {
    window.scrollTo(window.scrollX, window.scrollY - 100);
  });

  $('a[href*="#"]').on('click', function(event) {
    let hash = this.hash;
    if (hash) {
      event.preventDefault();
      $('html, body').animate({
        scrollTop: $(hash).offset().top - 100
      }, 750, function() {
        window.location.hash = hash;
      });
    }
  });
});

As it was suggested before, Microsoft Edge does not appear to properly support the .hash feature without causing some ill effects such as the rebounding of the smooth scroll feature. In order to work around this, I decided to use pushState for browsers that supported it, which achieved the desired effect.

HTML

<!DOCTYPE HTML>
<html lang="en">
<head></head>
<body id="home">
    <nav><a href="#section1">Section #1</a></nav>
    <main>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
        <h2 id="section1">section1</h2>
        <!-- INSERT A BUNCH OF <BR> TAGS -->
    </main>
</body>
</html>

CSS

nav {
    position: fixed;
    padding: 4px;
    border: 2px solid #000;
    width: 100%;
    line-height: 2.25em;
    background-color: yellow;
}

h2 {
    padding: 4px;
    border: 1px solid #000;
    width: 100%;
    line-height: 100px;
    background-color: red;
}

JAVASCRIPT

$('a[href*="#"]').click(function(event) {

    var href = $(this.hash);

    if (href.length) {
        event.preventDefault();
        $('html, body').animate({
            scrollTop: href.offset().top - 100
        }, 750, function() {
            if (history.pushState) {
                history.pushState(null, null, 'index.html#' + href.attr('id'));
            } else {
                location.hash = href.attr('id');
            }
        });     
    }
});

I was not able to figure out how to dynamically pull the calling file name, for example index.html or main.html to dynamically generate the hashed URL so that will have to be updated per page. Otherwise, this works exactly how I had expected. Please see the JSFiddle implementation for a working example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM