The bootstrap documentation on that topic is a little confusing to me. I want to achieve similar behaviour like in the docs with the affix navbar: The navbar is below a para
Just implemented this for the first time, and here's what I've found.
The data-offset-top
value is the amount of pixels that you must scroll in order for the affixing effect to take place. In your case, once 50px
is scrolled, the class on your item is changed from .affix-top
to .affix
. You'd probably want to set data-offset-top
to about 130px
in your use case.
Once this class change occurs, you must position your element in css by styling the positioning for class .affix
. Bootstrap 2.1 already defines .affix
as position: fixed;
so all you need to do is add your own position values.
Example:
.affix {
position: fixed;
top: 20px;
left: 0px;
}
My solution for attach the navbar :
function affixnolag(){
$navbar = $('#navbar');
if($navbar.length < 1)
return false;
h_obj = $navbar.height();
$navbar
.on('affixed', function(){
$navbar.after('<div id="nvfix_tmp" style="height:'+h_obj+'px">');
})
.on('unaffixed', function(){
if($('#nvfix_tmp').length > 0)
$('#nvfix_tmp').remove();
});
}
I was having a similar problem, and I believe I found an improved solution.
Don't bother specifying data-offset-top
in your HTML. Instead, specify it when you call .affix()
:
$('#nav').affix({
offset: { top: $('#nav').offset().top }
});
The advantage here is that you can change the layout of your site without needing to update the data-offset-top
attribute. Since this uses the actual computed position of the element, it also prevents inconsistencies with browsers that render the element at a slightly different position.
You will still need to clamp the element to the top with CSS. Furthermore, I had to set width: 100%
on the nav element since .nav
elements with position: fixed
misbehave for some reason:
#nav.affix {
position: fixed;
top: 0px;
width: 100%;
}
One last thing: When an affixed element becomes fixed, its element no longer takes up space on the page, resulting in the elements below it to "jump". To prevent this ugliness, I wrap the navbar in a div
whose height I set to be equal to the navbar at runtime:
<div id="nav-wrapper">
<div id="nav" class="navbar">
<!-- ... -->
</div>
</div>
.
$('#nav-wrapper').height($("#nav").height());
Here's the obligatory jsFiddle to see it in action.
To fix this very issue I have modified the affix plugin to emit a jQuery event when an object is affixed or unaffixed.
Here is the pull request: https://github.com/twitter/bootstrap/pull/4712
And the code: https://github.com/corbinu/bootstrap/blob/master/js/bootstrap-affix.js
And then do this to attach the navbar:
<script type="text/javascript">
$(function(){
$('#navbar').on('affixed', function () {
$('#navbar').addClass('navbar-fixed-top')
});
$('#navbar').on('unaffixed', function () {
$('#navbar').removeClass('navbar-fixed-top')
});
});
</script>
Thanks to namuol and Dave Kiss for the solution.
In my case I had a tiny problem with navbar height and width when I used afflix and collapse plugins together. The problem with width can be easily solved inheriting it from parent element (container in my case). Also I could manage to make it collapsing smoothly with a bit of javascript (coffeescript actually). The trick is to set wrapper height to auto
before collapse toggle occurs and fix it back after.
Markup (haml):
#wrapper
#navbar.navbar
.navbar-inner
%a.btn.btn-navbar.btn-collapse
%span.icon-bar
%span.icon-bar
%span.icon-bar
#menu.nav-collapse
-# Menu goes here
CSS:
#wrapper {
width: inherit;
}
#navbar {
&.affix {
top: 0;
width: inherit;
}
}
Coffeescript:
class Navigation
@initialize: ->
@navbar = $('#navbar')
@menu = $('#menu')
@wrapper = $('#wrapper')
@navbar.affix({offset: @navbar.position()})
@adjustWrapperHeight(@navbar.height())
@navbar.find('a.btn-collapse').on 'click', () => @collapse()
@menu.on 'shown', () => @adjustWrapperHeight(@navbar.height())
@menu.on 'hidden', () => @adjustWrapperHeight(@navbar.height())
@collapse: ->
@adjustWrapperHeight("auto")
@menu.collapse('toggle')
@adjustWrapperHeight: (height) ->
@wrapper.css("height", height)
$ ->
Navigation.initialize()
I've got this from the twitterbootstrap's source code and it's working pretty well:
HTML:
<div class="row">
<div class="span3 bs-docs-sidebar">
<ul id="navbar" class="nav nav-list bs-docs-sidenav">
...
</ul>
</div>
</div>
CSS:
.bs-docs-sidenav {
max-height: 340px;
overflow-y: scroll;
}
.affix {
position: fixed;
top: 50px;
width: 240px;
}
JS:
$(document).ready(function(){
var $window = $(window);
setTimeout(function () {
$('.bs-docs-sidenav').affix({
offset: {
top: function (){
return $window.width() <= 980 ? 290 : 210
}
}
})
}, 100);
});