Display menu items with equal widths

If you’d like all your menu items to be the same size, you use a percentage as the width. If you have 4 menu items, you set the width of each menu item to be 25% in your CSS.

But what if you add another menu item? The fifth one drops to another line since it doesn’t fit. You could use Javascript to count and resize them, but then you’d get a flash of unstyled content while the Javascript waits for the page to finish loading.

Or, you can use the built-in WordPress filters to do it. We’re using the nav_menu_css_class filter to customize the classes on the menu items.

<?php
/*
* Equal Sized Menu Items
* @author Bill Erickson
* @link http://www.billerickson.net/menu-item-equal-widths/
*
* @param array $classes, current menu classes
* @param object $item, current menu item
* @param object $args, menu arguments
* @return array $classes
*/
function be_equal_sized_menu_items( $classes, $item, $args ) {
// Only run on the header menu
if( 'header' !== $args->theme_location )
return $classes;
// Only run on top level menu items
if( $item->menu_item_parent )
return $classes;
// Grab all menu items
$menu_items = wp_get_nav_menu_items( $args->menu->term_id );
// Remove submenu items
foreach( $menu_items as $i => $menu_item )
if( $menu_item->menu_item_parent )
unset( $menu_items[$i] );
// Count all top level items, and add as a class
$classes[] = 'count-' . count( $menu_items );
return $classes;
}
add_filter( 'nav_menu_css_class', 'be_equal_sized_menu_items', 10, 3 );
view raw functions.php hosted with ❤ by GitHub
.genesis-nav-menu .menu-item.count-2 {
width: 50%;
}
.genesis-nav-menu .menu-item.count-3 {
width: 33.3333%;
}
.genesis-nav-menu .menu-item.count-4 {
width: 25%;
}
.genesis-nav-menu .menu-item.count-5 {
width: 20%;
}
.genesis-nav-menu .menu-item.count-6 {
width: 16.666666667%;
}
.genesis-nav-menu .menu-item.count-7 {
width: 14.285714286%;
}
.genesis-nav-menu .menu-item.count-8 {
width: 12.5%;
}
.genesis-nav-menu .menu-item.count-9 {
width: 11.111111111%;
}
.genesis-nav-menu .menu-item.count-10 {
width: 10%;
}
view raw style.css hosted with ❤ by GitHub

First I make sure that this is the ‘header’ menu location, since that’s the only menu I want to affect. I also make sure this is a top level menu item (I don’t want my submenus affected). I use wp_get_nav_menu_items() to get a list of all menu items in the menu, filter this list down to only top level menu items, count them up and add it as a class to the menu item.

So if you have 4 menu items, each one will have a class of “count-4”. If you add another menu item, they all will have a class of “count-5”. The CSS styles all the different variations: count-4 is 25% wide, count-5 is 20% wide…

This will work with any WordPress theme. Since I use Genesis, my CSS targets the .genesis-nav-menu. If you use a different theme just update this to match whatever class your nav menus have.

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Joan says

    Bill, now I love you even more. Pretty slick snippet, so you don’t have to change the CSS when adding a new menu item. Thanks SO MUCH for sharing.

    Best!

  2. Dave says

    Bill,
    Very clever! I haven’t had to make one of these OCD menus in awhile, but I sure could have used this!

    I look forward to the day that flexbox is better supported in CSS – then we can get something similar in CSS.

    Thanks, Dave

  3. Jens says

    This would be a good fit for table display.

    .item-wrap-selector {
    display: table;
    table-layout: fixed; /* Makes items equal width by default */
    width: 100%;
    }
    .menu-item-selector {
    display: table-cell;
    }

    Like a poor man’s flexbox, IE8 and up. Demo: http://codepen.io/anon/pen/NGKWNz.

    • Bill Erickson says

      Nice! I never use display:table so I wasn’t aware of that. I had considered flexbox but IE support kills that for important elements like nav menus

  4. Evan Scheingross says

    What a beautiful, simple solution!

    I’ve ran into this exact same problem before but failed to come up with something as clever as this nice little script. Definitely going to be applying this one in some future builds.

    Thanks for sharing Bill!

  5. Manuel says

    Thank you some much for sharing this! I Love it!

    This will be the next stored and mostly used snippet in my IDE!

  6. Philip says

    Absolutely brilliant. I have always had to use too many lines of CSS to solve this annoying issue and it was never really perfect if clients changed amount of tabs.

    Thank for this!

  7. Victor Marsala says

    Perhaps this is really elementary, but at what point where the paramaters of the original function defined? Are they being fed by the class you hooked into?

    • Bill Erickson says

      The ‘nav_menu_css_class’ filter runs when the menu items are being built (see here). We’re adding our own custom classes to it using the be_equal_sized_menu_items() function.

      Then in the stylesheet, we’re targeting those custom classes with additional styling.

      Hope that helps

  8. bravokeyl says

    Since many modern browsers supports Flexbox(except IE ,10,edge have partial support). I think for this case we can use flexbox model