Twitter bootstrap sticky subnav becomes fixed before it should on shorter pages

I implemented an automatic subnav dashboard, taken directly from Bootstrap docs CSS and JS , on the site I'm working on. It is displayed in only one view, but it is a Rails view, so it is dynamically generated depending on which object is loaded.

What I found is that when the content that appears under the subnav line is long enough, the behavior of the subnav bar works as expected - the subnav-based class is added right when the subnav bar is scrolled out field of view.

If the page is smaller than this, however, the subnav panel will become fixed before it is out of sight, which creates a rather sharp jump, not to mention that you can see the space in which there was a panel that you should not see .

I have to add that I am using a fixed (main) navigation bar with appropriate consideration for body filling.

It seems that the problem is with the return value of $('.subnav').offset.top .

Can someone better with jQuery / JS help diagnose this, and come up with a way to make the subnav panel only fixed when it scrolls out of sight?

Javascript:

 var $win = $(window) , $nav = $('.subnav') , navTop = $('.subnav').length && $('.subnav').offset().top , isFixed = 0 , $hiddenName = $('.subnav .hide') processScroll() $nav.on('click', function () { if (!isFixed) setTimeout(function () { $win.scrollTop($win.scrollTop() - 47) }, 10) }) $win.on('scroll', processScroll) function processScroll() { var i, scrollTop = $win.scrollTop() if (scrollTop >= navTop && !isFixed) { isFixed = 1 $nav.addClass('subnav-fixed') $hiddenName.removeClass('hide') if (!$('.subnav li').hasClass('active')) { $('.subnav li:eq(1)').addClass('active') } } else if (scrollTop <= navTop && isFixed) { isFixed = 0 $nav.removeClass('subnav-fixed') $hiddenName.addClass('hide') $('.subnav li').removeClass('active') } } 

Replicating Bootstraps main nav and subnav - I saw this question, but I don't think it escapes the problem as it still uses .offset()

UPDATE:

Still out of luck. navTop still seems shorter as the page length gets shorter, which makes no sense since it uses offset().top . Is there anything about how this method works that I don't get?

UPDATE 2

It seems like this can be resolved with Bootstrap 2.1.0, as it will actually include a subnav panel as a real component, as well as a jQuery plugin for managing sticky behavior. However, I would like to understand why the offset () function is so unreliable.

+6
source share
1 answer

I also took the same JS codes and adapted them to my site (still under development). Here are some of the codes (working)

HTML

 <div class="fix_on_top"> <div class="container"> <ul class="breadcrumb"> <li><a href="#">Home</a> <span class="divider">/</span></li> <li><a href="#">Packages</a> <span class="divider">/</span></li> <li class="active">Professional courses - I am a breadcrumb; I'll fix myself below the top navbar when you scroll the page</li> </ul> </div> </div> 

LESS (CSS)

 .fixed_on_top { left: 0; right: 0; z-index: 1020; position: fixed; top:$navbarHeight; } 

Javascript

 var $window = $(window), $fix_on_top = $('.fix_on_top'), fixed_Top = $('.fix_on_top').length && $('.fix_on_top').offset().top - 40, isFixed = 0; process_scroll(); // hack sad times - holdover until rewrite for 2.1 $fix_on_top.on('click', function () { if (!isFixed) setTimeout(function () { $window.scrollTop($window.scrollTop() - 47) }, 10); }); $window.on('scroll', process_scroll); function process_scroll() { var i, scrollTop = $window.scrollTop(); if (scrollTop >= fixed_Top && !isFixed) { isFixed = 1; $fix_on_top.addClass('fixed_on_top'); } else if (scrollTop <= fixed_Top && isFixed) { isFixed = 0; $fix_on_top.removeClass('fixed_on_top'); } } 

I also adapted the source code (for another site) that works on THEAD (tables - I have one table per web page with id = "tablesortable")

 // Automatically add the class "fix_on_scroll" on #tablesortable thead if ($('#tablesortable thead').length) { var thead_cells = new Array(); $('#tablesortable thead').addClass('fix_on_scroll'); // Get the width of each cells in thead $('#tablesortable thead').find('td, th').each(function(i, v) { thead_cells.push($(this).width()); }); // Keep same with in tbody and tfoot $('#tablesortable tbody tr:first').children('td, th').each(function(i, v) { $(this).width(thead_cells[i]); }); $('#tablesortable tfoot tr:first').children('td, th').each(function(i, v) { $(this).width(thead_cells[i]); }); } // Fix all elements (with class .fix_on_scroll) just below the top menu on scroll // (Modified version from homepage of Twitter Bootstrap - js/application.js) var $window = $(window), $fix_on_scroll = $('.fix_on_scroll'), fixed_elem_top = $('.fix_on_scroll').length && $('.fix_on_scroll').offset().top - 26, isFixed = 0; process_scroll(); // hack sad times - holdover until rewrite for 2.1 $fix_on_scroll.on('click', function () { if (!isFixed) setTimeout(function () {$window.scrollTop($window.scrollTop() - 40)}, 10) }); $window.on('scroll', process_scroll); function process_scroll() { var i, scrollTop = $window.scrollTop(); if (scrollTop >= fixed_elem_top && !isFixed) { isFixed = 1; $fix_on_scroll.addClass('fixed_on_scroll'); // Keep original width of td/th if ($fix_on_scroll.is('thead')) { $fix_on_scroll.find('td, th').each(function(i, v) { $(this).width(thead_cells[i]); }); } } else if (scrollTop <= fixed_elem_top && isFixed) { isFixed = 0 $fix_on_scroll.removeClass('fixed_on_scroll') } } 

My (adapted) codes work. You can use them.

+2
source

Source: https://habr.com/ru/post/919960/


All Articles