41

I'm attempting to make a nav bar that appears at the bottom of the viewable page when the site is first loaded, then as the user scrolls down, the nav bar scrolls up, and eventually becomes fixed to the top. I'm using Bootstrap, just like this site, but I can't figure out how this site did it. Any help?

Here's the site with the nav bar I'm trying to emulate: http://www.blastprocessor.co.uk/

Here's my navigation html and css code:

HTML:

<div class="navbar navbar-fixed-top" id="navbar">
    <div class="navbar-inner">
        <div class="container">
            <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            </a>
            <div class="nav-collapse">
                <ul class="nav nav-pills">
                    <li class="active"><a href="#home">Home</a></li>
                    <li><a href="#service-link">Services</a></li>
                    <li><a href="#contact-link">Contact</a></li>
                </ul><!-- /.nav -->
            </div><!--/.nav-collapse -->
        </div><!-- /.container -->
    </div><!-- /.navbar-inner -->
</div><!-- /.navbar -->

And here's my CSS:

.navbar-fixed-top,.navbar-fixed-bottom{position:fixed; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none;}
.navbar .nav > li a{
    color:white; background:rgba(0,0,0,0.2); text-shadow:none; font-size:1.7em; font-family: marvel, serif; padding:.5em 1.3em; margin:1em 2em;
}
.navbar .nav > .active a:hover, .navbar .nav > li a:hover, .navbar .nav > .active a {
    color:white; ; background:#F90; text-shadow:none; font-size:1.7em; font-family: marvel, serif; padding:.5em 1.3em; margin:1em 2em;
}
.navbar .nav > li {padding:2em;}
.navbar.navbar-fixed-top .navbar-inner{background: rgba(255, 255, 255, 0);}
.navbar .nav, .navbar .nav > li {
    float:none;
    display:inline-block;
    *display:inline; /* ie7 fix */
    *zoom:1; /* hasLayout ie7 trigger */
    vertical-align: top;
    padding:0 2em;
}
.navbar-inner {text-align:center;}
.navbar .navbar-inner, .navbar .navbar-inner {border: none; box-shadow: none; filter: none;}
SoEzPz
  • 14,958
  • 8
  • 61
  • 64
Brian
  • 2,687
  • 9
  • 37
  • 39

10 Answers10

41

I was searching for this very same thing. I had read that this was available in Bootstrap 3.0, but I was having no luck in actually implementing it. This is what I came up with and it works great. Very simple jQuery and Javascript.

Here is the JSFiddle to play around with... http://jsfiddle.net/CriddleCraddle/Wj9dD/

The solution is very similar to other solutions on the web and StackOverflow. If you do not find this one useful, search for what you need. Goodluck!

Here is the HTML...

<div id="banner">
  <h2>put what you want here</h2>
  <p>just adjust javascript size to match this window</p>
</div>

  <nav id='nav_bar'>
    <ul class='nav_links'>
      <li><a href="url">Sign In</a></li>
      <li><a href="url">Blog</a></li>
      <li><a href="url">About</a></li>
    </ul>
  </nav>

<div id='body_div'>
  <p style='margin: 0; padding-top: 50px;'>and more stuff to continue scrolling here</p>
</div>

Here is the CSS...

html, body {
  height: 4000px;
}

.navbar-fixed {
  top: 0;
  z-index: 100;
  position: fixed;
  width: 100%;
}

#body_div {
  top: 0;
  position: relative;
  height: 200px;
  background-color: green;
}

#banner {
  width: 100%;
  height: 273px;
  background-color: gray;
  overflow: hidden;
}

#nav_bar {
  border: 0;
  background-color: #202020;
  border-radius: 0px;
  margin-bottom: 0;
  height: 30px;
}

//the below css are for the links, not needed for sticky nav
.nav_links {
  margin: 0;
}

.nav_links li {
  display: inline-block;
  margin-top: 4px;
}

.nav_links li a {
  padding: 0 15.5px;
  color: #3498db;
  text-decoration: none;
}

Now, just add the javacript to add and remove the fix class based on the scroll position.

$(document).ready(function() {
  //change the integers below to match the height of your upper div, which I called
  //banner.  Just add a 1 to the last number.  console.log($(window).scrollTop())
  //to figure out what the scroll position is when exactly you want to fix the nav
  //bar or div or whatever.  I stuck in the console.log for you.  Just remove when
  //you know the position.
  $(window).scroll(function () { 

    console.log($(window).scrollTop());

    if ($(window).scrollTop() > 550) {
      $('#nav_bar').addClass('navbar-fixed-top');
    }

    if ($(window).scrollTop() < 551) {
      $('#nav_bar').removeClass('navbar-fixed-top');
    }
  });
});
SoEzPz
  • 14,958
  • 8
  • 61
  • 64
24

Note (2015): Both question and the answer below apply to the old, deprecated version 2.x of Twitter Bootstrap.

This feature of making and element "sticky" is built into the Twitter's Bootstrap and it is called Affix. All you have to do is to add:

<div data-spy="affix" data-offset-top="121">
  ... your navbar ...
</div>

around your tag and do not forget to load the Bootstrap's JS files as described in the manual. Data attribute offset-top tells how many pixels the page is scrolled (from the top) to fix you menu component. Usually it is just the space to the top of the page.

Note: You will have to take care of the missing space when the menu will be fixed. Fixing means cutting it off out of your page layer and pasting in different layer that does not scroll. I am doing the following:

<div style="height: 77px;">
  <div data-spy="affix" data-offset-top="121">
    <div style="position: relative; height: 0; width: 100%;">
      <div style="position: absolute; top: 0; left: 0;">
        ... my menu ...
      </div>
    </div>
  </div>
</div>

where 77px is the height of my affixed component.

Marcin Skórzewski
  • 2,854
  • 1
  • 17
  • 27
11

//in html

<nav class="navbar navbar-default" id="mainnav">
<nav>

// add in jquery

$(document).ready(function() {
  var navpos = $('#mainnav').offset();
  console.log(navpos.top);
    $(window).bind('scroll', function() {
      if ($(window).scrollTop() > navpos.top) {
       $('#mainnav').addClass('navbar-fixed-top');
       }
       else {
         $('#mainnav').removeClass('navbar-fixed-top');
       }
    });
});

Here is the jsfiddle to play around : -http://jsfiddle.net/shubhampatwa/46ovg69z/

EDIT: if you want to apply this code only for mobile devices the you can use:

   var newWindowWidth = $(window).width();
    if (newWindowWidth < 481) {
        //Place code inside it...
       }
VipinKundal
  • 442
  • 6
  • 14
Shubham Patwa
  • 334
  • 2
  • 6
6

Bootstrap 4 - Update 2020

The Affix plugin no longer exists in Bootstrap 4, but now most browsers support position:sticky which can be used to create a sticky after scoll Navbar. Bootstrap 4 includes the sticky-top class for this...

https://codeply.com/go/oY2CyNiA7A

Bootstrap 3 - Original Answer

Here's a Bootstrap 3 example that doesn't require extra jQuery.. it uses the Affix plugin included in Bootstrap 3, but the navbar markup has changed since BS2...

<!-- Content Above Nav -->
<header class="masthead">

</header>           


<!-- Begin Navbar -->
<div id="nav">
  <div class="navbar navbar-default navbar-static">
    <div class="container">
      <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
      <a class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
        <span class="glyphicon glyphicon-bar"></span>
        <span class="glyphicon glyphicon-bar"></span>
        <span class="glyphicon glyphicon-bar"></span>
      </a>
      <div class="navbar-collapse collapse">
        <ul class="nav navbar-nav">
          <li class="active"><a href="#">Home</a></li>
          <li class="divider"></li>
          <li><a href="#">Link</a></li>
          <li><a href="#">Link</a></li>
        </ul>
        <ul class="nav pull-right navbar-nav">
          <li>
            ..
          </li>
          <li>
            ..
          </li>
        </ul>
      </div>        
    </div>
  </div><!-- /.navbar -->
</div>

Working demo/template: http://bootply.com/69848

Carol Skelly
  • 351,302
  • 90
  • 710
  • 624
5

This worked great for me. Don't forget to put a filler div in there where the navigation bar used to be, or else the content will jump every time it's fixed/unfixed.

function setSkrollr(){
    var objDistance = $navbar.offset().top;
    $(window).scroll(function() {
        var myDistance = $(window).scrollTop();
        if (myDistance > objDistance){
            $navbar.addClass('navbar-fixed-top');
        }
        if (objDistance > myDistance){
            $navbar.removeClass('navbar-fixed-top');
        }
    });
}
kaleazy
  • 5,922
  • 2
  • 47
  • 51
4

Use Bootstrap Affix:

/* Note: Try to remove the following lines to see the effect of CSS positioning */
  .affix {
      top: 0;
      width: 100%;
  }

  .affix + .container-fluid {
      padding-top: 70px;
  }
<!DOCTYPE html>
<html>
<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  
</head>
<body>

<div class="container-fluid" style="background-color:#F44336;color:#fff;height:200px;">
  <h1>Bootstrap Affix Example</h1>
  <h3>Fixed (sticky) navbar on scroll</h3>
  <p>Scroll this page to see how the navbar behaves with data-spy="affix".</p>
  <p>The navbar is attached to the top of the page after you have scrolled a specified amount of pixels.</p>
</div>

<nav class="navbar navbar-inverse" data-spy="affix" data-offset-top="197">
  <ul class="nav navbar-nav">
    <li class="active"><a href="#">Basic Topnav</a></li>
    <li><a href="#">Page 1</a></li>
    <li><a href="#">Page 2</a></li>
    <li><a href="#">Page 3</a></li>
  </ul>
</nav>

<div class="container-fluid" style="height:1000px">
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
  <h1>Some text to enable scrolling</h1>
</div>

</body>
</html>
Deepak swain
  • 3,380
  • 1
  • 30
  • 26
3

You could use position: sticky

#navbar {
  position: sticky;
  top: 0px;
}

The #navbar should be a direct child of the body though.

Klaasvaak
  • 5,634
  • 15
  • 45
  • 68
3

For Bootstrap 4, a new class was released for this. According to the utilties docs:

Apply the class sticky-top.

<div class="sticky-top">...</div>

For further navbar position options, visit here. Also, keep in mind that position: sticky; is not supported in every browser so this may not be the best solution for you if you need to support older browsers.

mckenna
  • 159
  • 1
  • 7
1

In answer to Shubham Patwa: This way, the page is "jumpy" soon as the class "navbar-fixed-top" applies. That's because the #mainnav is throwen in and out of the document's DOM flow. This can result in an ugly UX if the page has a "critical height", jumping between fixed and un-fixed #mainnav position.

I altered the code this way, which seems to work fine (not pixel-perfect, but fine):

$(document).ready(function() {
  var navpos = $('#mainnav').offset();
  var navheight = $('#mainnav').outerHeight();

$(window).bind('scroll', function() {
  if ($(window).scrollTop() > navpos.top) {
   $('#mainnav').addClass('navbar-fixed-top');
   $('body').css('marginTop',navheight);
   }
   else {
     $('#mainnav').removeClass('navbar-fixed-top');
     $('body').css('marginTop','0');
   }
});
Traumkunst
  • 11
  • 2
0

I have found this simple javascript snippet very useful.

$(document).ready(function()
{
    var navbar = $('#navbar');

    navbar.after('<div id="more-div" style="height: ' + navbar.outerHeight(true) + 'px" class="hidden"></div>');
    var afternavbar = $('#more-div');

    var abovenavbar = $('#above-navbar');

    $(window).on('scroll', function()
    {
        if ($(window).scrollTop() > abovenavbar.height())
        {
            navbar.addClass('navbar-fixed-top');
            afternavbar.removeClass('hidden');
        }
        else
        {
            navbar.removeClass('navbar-fixed-top');
            afternavbar.addClass('hidden');
        }
    });
});
Valdrinium
  • 1,398
  • 1
  • 13
  • 28