Use the coupon code BLACKFRIDAY40 and save 40% OFF! Buy Now

How to style a WordPress navigation menu bar using CSS

Last Updated On
How to style a WordPress navigation menu bar using CSS WordPress template

Writing styles for navigation menus nowadays is mostly a routine job; after all, CSS has made strides in the last few years, we can even mimic hover-intent on menus without any JavaScript at all (a topic which we’ll cover on a dedicated tutorial).

WordPress isn’t much different, the native menu functionality is powerful and versatile enough to give us with exactly the HTML we’d require, plus a few more options for providing a better user experience to our users. The aim of this post is to take you through those and provide a complete solution on how to style a native WordPress navigation menu.

Adding a WordPress menu to our website

Displaying a nav menu on your WordPress site is generally very simple, it only takes a couple of lines:

<?php
// functions.php
register_nav_menus( array(
'main' => __( 'Main Menu', 'mytheme' ),
) );
?>

<?php // somewhere in header.php ?>
<header class="header">
<nav class="nav">
<?php
if ( has_nav_menu( 'main' ) ) {
wp_nav_menu( array(
'theme_location' => 'main-menu',
'container' => '',
'menu_class' => 'navigation-main',
) );
}
?>
</nav>
</header>
Adding a WordPress nav menu

Then all you have to do is go through the usual process of creating a menu and adding items to it via the admin dashboard.

For this tutorial we’ll assume our menu’s structure is as follows:

├── Home
├── Blog
|   ├── News
|   ├── Sports
|   ├── Fashion
|   |   ├── Article #1 Title
|   |   ├── Article #1 Title
|   ├── Business
├── About
└── Contact

So basically a menu of three levels (our final styles will support infinite nested levels). This would produce roughly the following markup:

<header class="header">
<nav class="nav">
<ul class="navigation-main">
<li class="current-menu-item">
<a href="#">Home</a>
</li>
<li class="menu-item-has-children">
<a href="#">Blog</a>
<ul>
<li><a href="#">News</a></li>
<li><a href="#">Sports</a></li>
<li class="menu-item-has-children">
<a href="#">Fashion</a>
<ul>
<li><a href="#">Article #1</a></li>
<li><a href="#">Article #2</a></li>
</ul>
</li>
<li><a href="#">Business</a></li>
</ul>
</li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
</header>
Final HTML markup

I said “roughly” before, and that’s because although the actual HTML structure will remain the same throughout our website, WordPress will add very specific classes depending on what page we’re currently viewing.

We need to keep in mind that WordPress adds the following three important classes to the menu’s <li> elements with the following rules:

  • .menu-item-has-children: Menu items that contain sub-items (just like “Blog” and “Fashion” in our example).
  • .current-menu-item: Menu items that correspond to the currently viewed page (so in our example we just opened the homepage as “Home” contains this class).
  • .current-menu-ancestor: Menu items that are ancestors (parents, grandparents) of the menu item which corresponds to the currently rendered page.

We’ll very soon see how to use these classes in our stylesheets.

WordPress also adds a few other classes that generally do not concern us in a normal menu, but can become useful in very specific use-cases so be sure to check them out.

Giving the menu some structure

With the markup in place it’s time to start styling our menu. We’ll be using Sass instead of vanilla CSS. Sass comes very handy here, especially in styling menus where there’s a lot of nesting involved. It’s extra useful because (as with most things in WordPress) we need to style everything on our menu under its main class namespace (.navigation-main). This will prevent our styles from “bleeding” out to other potential menus we might have in our theme.

In general, when I write styles for a navigational component with a complex functionality I like to split styles into blocks “structure/functionality” and “presentation/appearance” styles, even if that means that I have to be a bit more verbose or even duplicate some selectors. I’ve found that it provides a clear separation of concerns and becomes a much more maintainable paradigm, especially when the component’s presentational requirements become very complex (think animations, different colors for each sub-item, etc). We’re not going to deal with that kind of stuff right now, but it’s a good practice to have in mind when the CSS concerns are so cleanly separated in a particular isolated component such as this one.

.header {
display: flex;
align-items: center;
}

.nav {
width: 100%;
}

.navigation-main {
//
// Structural Styles
//
margin: 0;
padding: 0;
list-style: none;
width: 100%;
text-align: center;

ul {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
left: -999em; // "Hide" the sub-menus
}

li {
display: inline-block;
position: relative;
text-align: left; // Reset text alignment

// First sub-menus appear below the menu item
&:hover {
> ul {
left: auto;
}
}

// All other levels appear on the right
li {
display: block;

&:hover {
> ul {
left: 100%;
top: 0;
}
}
}
}

//
// Presentational Styles (we'll add them soon)
//
}
The menu's main structural styles

This is all it takes to imbue the functionality of a standard navigation menu, and support infinite nested levels. We absolutely position all sub-menus, offset them out of screen (we don’t set their display property to “none”) and we reposition them on hover making them visible.

Here’s how this all looks:

0

Try hovering over “Blog”, and then “Fashion”.

It’s kinda ugly though, so let’s make it a bit prettier.

Adding appearance and visual clues to the menu

Pretty basic stuff, some background and link colors:

$background-color: #145474 !default;
$link-color: #fff !default;
$link-active-color: #ffcc03 !default;

.header {
background-color: $background-color;
display: flex;
align-items: center;
}

.nav {
width: 100%;
}

.navigation-main {
//
// Structural Styles
//

// Same as what we wrote before

//
// Presentational Styles
//

// Global menu link styles
a {
color: $link-color;
text-decoration: none;
display: block;
white-space: nowrap;
padding: 10px 15px;
}

// Active & hover styles
a:hover {
color: $link-active-color;
}

// Submenu styles
ul {
background-color: $background-color;
}
}

And here’s how it looks now:

0

Although our menu is starting to look good it’s missing a couple of things which are quite important for a good user experience.

First of all, it would be nice if while the user hovers over different nav items their parents and ancestors remain highlighted. It helps with visual identification of the current hovered path and it just looks better, so let’s fix that with the following extra selector:

...

// Active & hover styles
a:hover,
li:hover > a { // This trick keeps all active nodes in the navigation path colored active
color: $link-active-color;
}

...
Highlighting the currently hovered path

Secondly, we must highlight the nav items which correspond to the currently viewed page. That means that, if a user is at “Home” we should highlight the “Home” item, and if a user is viewing “Article #1” the menu should highlight all its ancestors up to and including “Blog”.

Here’s where the classes we mentioned before come into play, and it’s very simple to handle the above scenarios:

...

// Active & hover styles
a:hover,
li:hover > a,
.current-menu-item > a,
.current-menu-ancestor > a {
color: $link-active-color;
}

...
Highlighting current menu items and their ancestors

Check out how “Home” now remains active and how if you navigate all the way through “Article #1” its ancestors will also stay highlighted:

0

Adding visual clues for items with children

It’s also a standard good practice to provide a visual clue (such as an arrow) for items with nested sub-menus. The tricky part here is that items belonging to the first level (main menu) should have arrows pointing down, while the rest should point right. As a final step let’s see how we’d go about this:

...

// First level item arrows
.menu-item-has-children {
> a {
&::before {
content: "";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
border: 4px solid transparent;
border-top-color: currentColor; // Nifty trick to always keep the arrow colored the same as the menu item's text in every different state
}
}
}

// Second level item arrows
ul {
.menu-item-has-children {
> a {
&::before {
right: 2px;
border-top-color: transparent;
border-left-color: currentColor;
}
}
}
}

...
Adding dropdown arrows

Note that I’m creating CSS triangles with the border trick but you’re free to use whatever you wish, e.g. FontAwesome icons (fa-angle-down is a good choice).

And the result:

0

Pretty good! Looks like we’re all done with our menu, perfectly styled and ready for deployment.

Going the extra mile: Making the menu accessible

Our menu is pretty much finished but it would be awesome if we could make it accessible to keyboard users, navigating with the tab button. For this we’ll need to write some very basic JavaScript and only add a couple of classes to our CSS:

jQuery(function ($) {
var siteNavigation = $('.navigation-main');

siteNavigation.find( 'a' ).on( 'focus blur', function() {
$( this ).parents( 'li' ).toggleClass( 'focus' );
});
});
Making the menu accessible is easy!

This toggles a class on a menu item every time we focus on its link. This way we can simply alter our CSS to display the sub-menus when that class is present:

...

li {
display: inline-block;
position: relative;
text-align: left; // Reset text alignment

&.focus, // Display the menus both on hover and when .focus is present!
&:hover {
> ul {
left: auto;
}
}

li {
display: block;

&.focus,
&:hover {
> ul {
left: 100%;
top: 0;
}
}
}
}

...

a:hover,
li:hover > a,
.focus > a, // And color them as well
.current-menu-item > a,
.current-menu-ancestor > a {
color: $link-active-color;
}

...

And we’re done! Let’s look at a complete example with more nested levels and the current menu item on a lower level than the main menu. Try hovering over and tabbing through and it should all work great!

0

Let us know in the comments how you prefer to style your WordPress menus or any tips and tricks you might have up your sleeve, and, oh! if you’d also like to convert your menu into a mobile drawer for mobile devices we’ve got you covered :)

63 responses to “How to style a WordPress navigation menu bar using CSS”

  1. Thanks i must say am using it on my blog now and the menu is awesome

  2. Mavislibrary says:

    Thanks For THis article. With this, i can be able to modify and make some changes on my theme by myself.

  3. Feeroz Hasan says:

    Hello, Sir,
    Kindly solve my problem. I am using Unconditional WordPress theme. It doesn’t support the second level of the menu. I am not able to navigate to subpages. I like this theme and don’t want to change it but the sub-menu problem is existing.
    Kindly help.

    Regards

  4. AI Sudin says:

    Great post. Extremely helpful. But how can we make this menu responsive?

    • Vassilis Mastorostergios says:

      Thanks for the kind comments! Making a menu responsive is kind of a custom deal as you’d need to know your requirements before doing so, you could get away with a simple display: block on everything and implement some JavaScript in order to hide/show the menu entirely on click or you can use the magnificent jQuery mmenu plugin http://mmenu.frebsite.nl/ which is our choice as well.

  5. Ikechukwu says:

    I was able to modify my theme a little bit if customize it to my test using this particular guide.
    But I have a question to ask. Is it possible for Google to stop indexing your blog when a new theme is installed?
    Since I installed the theme my post is not coming up

  6. Rohi Arora says:

    Thanks for the article. How we can expand this code to mega menu?

    • Vassilis Mastorostergios says:

      Heya, glad you liked it. Implementing a mega menu is a bit more involved to fit in a comment, plus there’s all sorts of different mega menus around (images etc) so generally it’s up to the developer to do it, but the logic remains the same pretty much, in your child ul > li elements add a div element and content inside it :)

  7. Emily says:

    Hi, this was very helpful, as I’m just getting into CSS as I help a friend of mine with his business website (wordpress). One thing that has been bugging me though is the navigation “block”. There are 20 categories with dropdowns. It’s currently set to float, so it’s only taking up 4 rows on the page, but the “justification” is to the left. Just for aesthetic purposes, is there a way to set the navigation block so that each line of links is “centered” – so there’s the same amount of “padding” on the left and right of each line?

    • Vassilis Mastorostergios says:

      Hiya, you’d have to set display: flex on the ul.navigation and then justify-content: space-between.

  8. pierre says:

    Hello,

    Thank you for the tuto !
    I’ve got two probleme :
    The submenu disappear when the mouse left the parent element of the submenu. So when the mouse flies over an submenu item, the submenu disappear.
    The other probleme is the z-index. I don’t anderstand why the menu is under the other elements of the page, I think the probleme is dependant of my theme OKAB but if you have an issue for me it would be cool.

    Thanks

    • Vassilis Mastorostergios says:

      For the first issue I think you’ve added some kind of `margin` on your parent submenu elements and as such while the pointer leaves the element it loses hover state. Please try to check if you have some kind of margin and replace it with padding if possible.

      For the second issue unfortunately there’s no way to help you directly, you need to check which element has a higher z-index and what that z-index is and adjust the menu to use a higher one!

    • Isaac says:

      Are you using wordpress v5 ?

  9. Stevo says:

    I must confess, this post is helpful to me.

  10. Saheed says:

    Thank you very much for this post, I was able to fix some issues with it. Keep up the good work here.

  11. Victor says:

    What a great work there, it works perfectly well on my blog. Thanks

  12. Vicky says:

    What a great work there, it works perfectly well on my blog. Thanks

  13. Frank Daniel says:

    this guide worked perfectly for me
    i love this blog
    i hope to find another solution to my blog problem

  14. ema jame says:

    you just solve my problem I thank you ones again i love your website keep it up have bookmarked it

  15. What a great guide there, it works perfectly well on my blog. Thanks

  16. Master says:

    Thanks for sharing

  17. Usulor says:

    Wow! This is a great guide, this is what I have been searching for but actually I found it here, thanks bro.

  18. aadhi says:

    hi i need a solution for how to make navbars active for their respective pages in wordpress

  19. John says:

    Thanks for sharing this information with us it really helped me understand

  20. Peace David says:

    you just solve my problem I thank you ones again i love your website keep it up have bookmarked it

  21. Really good here, styling a WordPress website following your guide makes it super simple.

  22. john John says:

    wow, thanks man, you made everything easy for me, styling my blog to my taste hasn’t been easy

  23. Collins Bolt says:

    Hello,

    Thank you for the tuto !
    I’ve got two probleme :
    The submenu disappear when the mouse left the parent element of the submenu. So when the mouse flies over an submenu item, the submenu disappear.
    The other probleme is the z-index. I don’t anderstand why the menu is under the other elements of the page, I think the probleme is dependant of my theme OKAB but if you have an issue for me it would be cool.

    Thanks

    • Vassilis Mastorostergios says:

      Hello, we’d have to have some kind of code example or url to help out with the issue if there’s one available.

  24. Thompson says:

    Thanks for bringing up this article

  25. Joe says:

    Thanks for sharing this

  26. Joyous says:

    I really appreciate your time and effort on this article because it full of valuable information

  27. Thompson says:

    Please i need more update till on this topic

  28. Ekijazzy says:

    Very detailed article, I think with this i can actually modify and make some changes on my theme by myself.

  29. Roberta says:

    How to set it up for mobile as well? Adding some kind of “hamburger” style where the menu is collapsed on mobile devices, using a css break.

    Is that possible?

    • Nik says:

      Hello Roberta.
      This process is a bit more involved and outside the scope of this guide I’m afraid. However I can offer some info to help you proceed. On our themes we tend to use mmenu.js to help us with mobile menus. The site has quite a lot of information and examples on how to implement it on your site, and it also offers a WordPress plugin.

  30. Someone says:

    Well where do u post all these css codes?

    • Vassilis Mastorostergios says:

      Hello! Typically you would put them in your theme’s style.css or even better a child-theme’s style.css.

  31. If I update the theme, hope it would not be overriden?

    • Nik says:

      Hello Eddy.
      If you edited theme files directly then I’m afraid the answer is yes, if you update the theme changes will be lost. All changes should be made in a child theme (here’s a guide on how to create one) so they can be preserved after an update. If you only need CSS for your modifications you can place it in the “Additional CSS” section under Appearance -> Customize, this way you can preserve CSS changes without the need of a child theme.

  32. Joe Smith says:

    Sincerely I would say this site has been helpful

  33. Paul says:

    Hello I cannot login my account anymore please help

  34. John says:

    I would say this is the best site ever

  35. Oliver Smith says:

    Hi,

    What you Recommend the CSS which can load faster ? I have a blog where my sites load is too slow according to Google page speed site.

    • Nik says:

      Hello Oliver.
      You could try plugins like Autoptimize to minify and concatenate styles and scripts, additionally you could check out caching plugins for WordPress.
      Best regards.

  36. imolite says:

    Your article was really impressive. Do keep post like this…

  37. John Jiménez says:

    Hey man,

    A lot of thanks 4 ur coding, was very usefull and simple, I am retaken stuff about css and remember than before I had a lot of work with make this menu, but you really make it easier…

    Thx man…

  38. A pretty useful tutorial. Still very useful even in 2022.

  39. Emmaneul says:

    Very informative, Thanks for sharing. I think with this i can actually modify and make some changes on my theme by myself.

  40. sam35 says:

    can this still work for for my work

Leave a Reply

Your email address will not be published. Required fields are marked *

Get access to all WordPress themes & plugins

24/7 Support Included. Join 115,000+ satisfied customers.

Pricing & Sign Up

30-day money-back guarantee. Not satisfied? Your money back, no questions asked.

Back to top