Affix Flickering Problem in Bootstrap
The Problem
As of the current version of Bootstrap (V3.3.1) there exists an issue with Affix function and vertical scrolling. For certain vertical sizes of the document inside the browser window, scrolling down will have a flickering effect on the content. This happens right when the Affix element is supposed to stick to its position; instead you are met with an ugly scrolling action. You can see this behavior below.
Here’s the code used to capture the behavior above: http://codepen.io/anon/pen/raMJox. If you adjust the height of the browser to the right size you should be able to replicate this issue.
Diving Into Behavior
Affix works by replacing CSS classes on the Affix element when you
scroll past certain offset. In the example code above, the top offset
is set to 100px in affix
function because that’s the height of the
Header and we want the NavBar to stick to the top after you scroll
100px down, past the header.
$(".nav").affix({
offset: {
top: 100
}
});
When scrolling the document down exceeds the specified offset,
Bootstrap adds the CSS class affix
to the Affix element. If you look
at the CSS code for .affix
class you can see that the CSS property
position
is set to fixed
.
When an element is set to fixed, it’s removed from the regular flow of the layout in the browser. The space that the NavBar occupied in the original document is now gone. If the document height was 500px to begin with and the NavBar occupied 100px of it, after we make NavBar element fixed, the document height will become 400px.
You can check out this effect here: http://codepen.io/anon/pen/QwKKwv. Click the button in the NavBar to see the original height of the document. Scroll down until the NavBar is fixed on top and then click on the button again to see the document height. They should be different.
This document height re-adjustment causes an issue with Affix
function. Even though we just passed the 100px top offset and the
affix
CSS class was added to the NavBar element, Affix function
recalculates the current scroll position and finds that it’s less that
100px because of the removal of NavBar element from the layout due to
fixed positioning. Bootstrap removes affix
CSS class and adds back
affix-top
class to the NavBar element, which removes it from fixed
position and adds it back to the document layout. But adding NavBar
back to regular document flow increases the height of the document
again and the new scroll position is past 100px now which means
Bootstrap will add affix
CSS class back to NavBar element. This back
and forth addition and removal of affix
and affix-top
CSS classes
on NavBar causes the flickering issue.
The Fix
The fix is really simple. We just need to reserve the space in the original document layout for the Affix element no matter what type of positioning the Affix element has. Surround the Affix element with a div or any other block element having a height equal to the Affix element height. You can use either CSS or JavaScript to set the height of the wrapping element.
Option 1 Source: http://codepen.io/anon/pen/ogzqvo
<div class="nav-wrapper">
<div class="nav"> NavBar </div>
</div>
.nav-wrapper, .nav {
height: 60px;
}
$(".nav").affix({
offset: {
top: 100
}
});
Option 2 Source: http://codepen.io/anon/pen/YPGaKa
<div class="nav-wrapper">
<div class="nav"> NavBar </div>
</div>
$(".nav").affix({
offset: {
top: 100
}
});
$(".nav-wrapper").height($(".nav").height());
Note: If you have some other scripts that manipulate your Affix elements’ height, make sure to run them before you set the height on the wrapping element.