简体   繁体   中英

Smooth-scroll a bootstrap page with sticky navbar

Smooth-scroll scripts in common, stop the default link action (by returning false) to prevent a jump in the animation. This also stops bootstrap navbar menus to collapse when clicked on a link (bad).

Example:
http://www.bootply.com/NoGAvuQGDE

In the smooth scroll script's last line;

  • if you return false , it conflicts and stops the menu closing when clicked on a link.
  • If you return true , the animation gets jumpy due to the link working.

Reproduce:

  • click on the dropdown / action link
  • the dropdown stays open (bad), due to the blocked default action

Excluding navbar links from smooth-scrolling would beat the purpose.

Idea:
We could modify the smooth-scroll script to close all navbar menus when a link is smooth-scrolled. Something like $('.dropdown-toggle').dropdown('collapse') would work but there is no 'collapse' action in the API, only 'toggle'.

Q: How can I have smooth-scrolling on a bootstrap page, without it conflicting with navbar menus , stopping them close?


The smoothscroll script, for future reference :

$(function(){
    $('.navbar a[href*=#], a.smooth').click(function() {return smoothScroll(this)});
});

function smoothScroll(linkItem) {

    if (location.pathname.replace(/^\//,'') == linkItem.pathname.replace(/^\//,'')
    && location.hostname == linkItem.hostname) {

        var $target = $(linkItem.hash);
        $target = $target.length && $target || $('[name=' + linkItem.hash.slice(1) +']');

        if ($target.length) {
        var targetOffset = $target.offset().top;
        $('html,body').animate({scrollTop: targetOffset}, 500);
        return false;
        }
    }
}

Looking at the document tree while toggling the dropdown menu, the Bootstrap functionality seems to rely on an open class on the parent. In the relevant code concerning the event handlers (which is a bit obscure to read), this class is toggled. The following would emulate it when the default behaviour is prevented on a menu that is active and seems to be doing the trick :

dropdown = linkItem.closest('.dropdown');

if ($(dropdown).hasClass('open')) $(dropdown).removeClass('open');

One could argue the link is only clickable when the dropdown is open so even this should suffice :

$(dropdown).toggleClass('open');

A dropdown inside another one would need some additional script but I guess that's an unlikely configuration. Interaction with any siblings is apparently working well too. Integrated in the code :

$(function(){
    $('.navbar a[href*=#]').click(function() {return smoothScroll(this)});
});

function smoothScroll(linkItem) {

    if (location.pathname.replace(/^\//,'') == linkItem.pathname.replace(/^\//,'')
    && location.hostname == linkItem.hostname) {

        var $target = $(linkItem.hash);
        $target = $target.length && $target || $('[name=' + linkItem.hash.slice(1) +']');
        var dropdown = linkItem.closest('.dropdown');

        if ($target.length) {
        if (dropdown) $(dropdown).toggleClass('open');
        var targetOffset = $target.offset().top;
        $('html,body').animate({scrollTop: targetOffset}, 500);
        return false;
        }
    }
}

When only using this script on anchor links, it could be simplified by the way :

$(function(){
    $('.navbar a[href*=#]').click(function() {smoothScroll(this)});
});

function smoothScroll(linkItem) {

    var $target = $(linkItem.hash),
    dropdown = linkItem.closest('.dropdown');

    if ($target.length) {
    if (dropdown) $(dropdown).toggleClass('open');
    var targetOffset = $target.offset().top;
    $('html,body').animate({scrollTop: targetOffset}, 500);
    return false;
    }
}

While getting the expected results with what was posted in the comments earlier, after additional debugging the code needed to be a bit more subtle to find the correct parent - also added an extra if (dropdown) check. No need to apply a method on something that doesn't exist of course.

http://www.bootply.com/hC4s6OEgA1

One way to accomplish this is to add an additional class to the navigation menu items that need the smooth scrolling which will leave the other menu items that you dont want to scroll to work as intended.

Your updated navigation menu HTML

<ul class="nav navbar-nav">
  <li class="smooth"><a href="#a">About</a></li>
  <li class="smooth"><a href="#b">Contact</a></li>
  <li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
    <ul class="dropdown-menu">
      <li><a href="http://www.google.com" target="_blank">Action</a></li>
    </ul>
  </li>
</ul>

and your updated JQuery:

$(function(){
    $('.navbar .smooth a[href*=#], a.smooth').click(function() {return smoothScroll(this)});
});

I have added a JS.Fiddle if you want to see it working. Hope that helps.

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