The Blog

Creating a “Sticky” Navigation Bar with Headway

sticky_nav_feature

VIEW the DEMO

PROBLEM: Your navigation is one of the most important parts of your website. It’s how your visitors get from the homepage to other parts of your site! But once they scroll down to read your content, they can’t see the navigation anymore – and darn it, you want them to see it all the time!

SOLUTION: A sticky navigation bar. You see them all the time (not a Headway site), but how to implement? No worries; it’s actually pretty easy!

Step 1: Set up a WordPress & Headway site with a navigation bar.

Yeah that’s as easy as it sounds. If your site is already completed or in progress, you probably have a navigation bar. If you don’t, go ahead and add a navigation block now.

Step 2: Add a little jQuery Magic

This jQuery script is pretty well commented, but here’s the gist of it:

  1. Hi webpage! Are you being displayed on a mobile device? If you are, we won’t make the navigation sticky because dang, a sticky nav on a mobile device takes up too much room. Oh, you aren’t? Fabulous.
  2. Oh, the window is scrolling! That’s my cue. I’m looking for the .block-type-navigation class. You got one? You do? Fabulous! I’d like to add  a class to it, please. Thanks!
  3. Whoops, you scrolled back up the top. Let’s remove that class, huh? Thanks!

Basically once you scroll down, we are sticking the navigation to the top of the page & making it super obvious to the user that Hey! You! Can! Navigate! There’s more to see!

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function($) {
 //STICKY NAV
 var isMobile = {
 Android: function() {
 return navigator.userAgent.match(/Android/i) ? true : false;
 },
 BlackBerry: function() {
 return navigator.userAgent.match(/BlackBerry/i) ? true : false;
 },
 iOS: function() {
 return navigator.userAgent.match(/iPhone|iPad|iPod/i) ? true : false;
 },
 Windows: function() {
 return navigator.userAgent.match(/IEMobile/i) ? true : false;
 },
 any: function() {
 return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
 }
 };
//Calculate the height of <header>
 //Use outerHeight() instead of height() if have padding
 var aboveHeight = $('.top-row').outerHeight();

 //when scroll
 $(window).scroll(function(){

 //if scrolled down more than the header’s height but this isn't mobile
 if ($(window).scrollTop() > aboveHeight && !isMobile.any()){

 // if yes, add “fixed” class to the <nav>
 // add padding top to the #content 
 // (value is same as the height of the nav)
 $('.block-type-navigation').addClass('fixed').css('top','0').next()
 .css('padding-top','42px');

 } else {

 // when scroll up or less than aboveHeight,
 // remove the “fixed” class, and the padding-top
 $('.block-type-navigation').removeClass('fixed').next()
 .css('padding-top','0');
 }
 });
});
</script>

A Note on Loading jQuery

This code goes straight into the Header Scripts area of Headway -> Options. The first line ensures that jQuery is being loaded. If you are using a child theme & can load the script via the wp_enqueue function, that’s the preference and you can skip that line!

You could also skip the first script line in the code above (and start at the second < script >
tag), and put this line of code in the Footer Scripts area instead to load jQuery more cleanly. This will prevent jQuery from being loaded twice (and could fix any potential errors).

<?php
wp_enqueue_script('jquery-ui', '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js', false, false, true);
?>

Two Additional Notes!

Multiple Navigation Blocks: As written, it is going to affect *all* of your navigation blocks. SO if you have two of them on a page, it’s going to look for both! If you want only one of the navigation bars to be affected however, that’s no problem. Just add a custom class to your navigation block (open up the Block Options for the navigation block, and add something in the Config -> Custom Classes input). Then you’ll replace .block-type-navigation with .[yourClassGoesHere]. So if you gave your block a class of stickyNav, your jQuery code would read something like: $(‘.stickyNav’).addClass(‘fixed’).css(‘top’,’0′).next() instead of $(‘.block-type-navigation’).addClass(‘fixed’).css(‘top’,’0′).next(). Remember, there are two places this gets changed in the script!

Taller Navigations Blocks: By default this script is set for a navigation block that is around 42px high. If your navigation block is taller/shorter and this isn’t behaving the way you expect it to, change the line that says “ .css(‘padding-top’,’42px’);” — you’ll change 42 for the height of your navigation block.

Step 3: Add a Little Custom CSS Magic

Finally we need just a teeny little bit of CSS to make this look fabulous & for it to stick! In Design Mode, open up the Live CSS Editor and drop in this code:

.fixed {
     position:fixed !important;
      left: 0;
      text-align: center;
}
.fixed .block-content {
      display: inline-block;
      text-align: left;
      width: 940px; /* This should be the width of your grid!!! */
      float:none;
}

The only part of this you’ll need to change is the width — that should be equal to the width of your grid.

Step 4: You’re done!

Aside from lording it over your friends that you just created a sticky nav … you’re all set! Post your site in the comments so we can see how great your site looks!

Spread the word!

By adding a comment below, you agree to abide by our comment policy.

34 comments
praveen_ramachandran
praveen_ramachandran

Well, I've to add z-index: higher-number to make sure that the header isn't looking messed up like a see through glass. This must be the 'messed up' aspect in the comment by Lazlo.

Lazlo Toth
Lazlo Toth

Thanks for your post. I have a couple of questions. I viewed your demo on two different browsers (FireFox 19 and Safari 5) and it looks pretty messed up and unprofessional in the way that it jumps when you start to scroll. Is this normal? Also, why do I see two copies of your header when I scroll...and why is one of them transparent. Here is a screencast that shows exactly what I am describing: https://www.youtube.com/watch?v=OhKUMaYM-DQ

Ben S
Ben S

(Apologies for the massive post) I was searching around for something like this and came across a few different scripts, and I think I may have found a simpler way of toggling the class and calculating when to switch the class. This way it calculates where the top of the main-nav (custom class) is and switches the class when the window reaches it. It doesn't affect the navigation wrap either (which was causing my layout to jump around before), instead it leaves the wrap and moves the .block-content.

I also kept the first part of your script to check for mobile devices and added it in.

My only problem is that the submenu drop down animation seems to have stopped working - so, I'm not sure if I'm loading jQuery properly? I tried taking out the first line and adding that other script to the footer like you suggest, but it seems to stop this script from working?

This is the first time I've played around with jQuery properly, so I'm not 100% sure if this is better or not? Here's the script I'm using (and a demo in jsFiddle: http://jsfiddle.net/zZUMS/5/):


<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<script type="text/javascript">

//STICKY NAV

//when window scrolls

$(document).scroll(function() {

    // CALCULATE distance of main-nav from top of viewable window

    var menuTop = $(".main-nav").offset().top; - $(window).scrollTop();

    //if scrolled down more than main-nav & not mobile then toggle class

    var useStickyNav = $(document).scrollTop() > menuTop  && !isMobile.any();

    $('.main-nav .block-content').toggleClass('sticky-nav', useStickyNav);

});


</script>

champen
champen

slideshow shows in front of the menubar and hides it when i use this?

richardvav
richardvav like.author.displayName 1 Like

@champen You need to edit the css for the .fixed class and add a z-index such as

z-index:99999;

richardvav
richardvav

Using the above as soon as you start to scroll the menu becomes sticky, I guess because the class .top-row doesn't actually exist so you should switch from using the class .top-row to using the actual header element that way it only switches to sticky when the actual height of the header element has been scrolled and not before

var aboveHeight = $('.top-row').outerHeight();

should be

var aboveHeight = $('header').outerHeight();

caitlinheadway
caitlinheadway

@richardvav Good point Richard :) I was using a .top-row in my dev environment at some point but failed to explain that part of my code :) 


If your navigation is not at the top of the screen, you'll want to change the line there based on the element above the navigation, like .block-type-header (.header won't do anything unless you define a custom class)

Latest blog post: Sign Up | Headway Toolbox

Frank Warwick
Frank Warwick

I am using Tabsplus in my site and there are conflict issues

If I put the jquery link in the header, tabsplus does not work, if I put jquery link in the footer the menu does not work on the pages that Tabsplus is not on.

Any ideas?

caitlinheadway
caitlinheadway

@Frank Warwick Sounds like jQuery is already being loaded, try skipping loading the jQuery script entirely

Latest blog post: Sign Up | Headway Toolbox

cosmintataru
cosmintataru

Hello !

One small suggestion: add z-index:100; under the .fixed class to make sure the menu is always on top. :)

Latest blog post:

LeftoverCake
LeftoverCake

Firstly, thank you for the code. Your explanation was very clear... It took a little tweaking around with but I was able to get it to work...

 

My question is how hard would it be to "brand" the floating nav-bar with a logo that floats to the left or right of the menu text or maybe social icons? Should this be feasible? Or is this treading into the 'extraneous coding' area? Thanks in advance for any pointers! :)

Latest blog post: The Future Of DropTheR.net

GetGoHelp
GetGoHelp

Nice and useful tut. :)

 

So the Jquery code?  We have to insert the code you show us into the header option of Headway?

 

Thanks :)

afroniquely
afroniquely

YAYYYYYY!!! Thanks so much @caitlinheadway I will be trying this and I am hoping for good results. I like @ramonahux would love to know how to make them separate. So say on my site, I would just have two separate menus? The main menu and then another one that would be the pop-up overlay menu? But I would have to hide it you say via responsive grid hiding? Not sure how to target the right one and also make it appear and such.

ramonahux
ramonahux like.author.displayName 1 Like

Hi, 

Is there a tweak for this that would allow a separate menu to appear upon scrolling down? 

Such as here: http://www.interviewmagazine.com/#_

and here: http://apairandasparediy.com/

 

Mona

caitlinheadway
caitlinheadway like.author.displayName 1 Like

 @ramonahux You would want to target a different navigation block, one that you hid from view by default using CSS or the Responsive Grid block hiding. See my note about multiple navigation blocks for a tip on how to target a specific navigation block. 

Latest blog post: Sign Up | Headway Toolbox

ramonahux
ramonahux

 @caitlinheadway Hi Caitlin,

I've tried this with responsive grid hiding but it doesn't work. The navigation bar merely remains hidden. Is there any CSS you could provide to initially hide the second bar until the user scrolls down? 

ramonahux
ramonahux

 @caitlinheadway Hi Caitlin,

Sorry about this. But I have turned on Responsive Grid hiding and entered all the code as above but it isn't working. The second menu stays either completely hidden (when responsive grid hiding is on) and doesn't appear on scroll or (when responsive grid hiding is off) is constantly present...

caitlinheadway
caitlinheadway

 @ramonahux sorry I got all these notifications at the same time :-D 

 

You need to add an extra line to the CSS for the .fixed class above - 

 

.fixed {

position:fixed !important;    

 left: 0;      

text-align: center;

display: block !important;

}

Latest blog post: Sign Up | Headway Toolbox

ramonahux
ramonahux

 @caitlinheadway  @ramonahux Thank you for your response. Where would I find the responsive grid hiding? 

ramonahux
ramonahux

 @caitlinheadway I do not seem to have the Resposive Grid option to hide a block in the config. Would you be able to point me towards some CSS to hide the block by default?

WeekendProducer
WeekendProducer

I sent demo page to my Android device and the page is shown in the same way as on the desktop. Nothing changes. It doesn't "response" to my mobile.