How to Add Icons to WordPress Custom Menus Without Plugins

WordPress Custom Menu - Icons

It’s easier than you might think.

Adding icons to WordPress custom menus is a relatively simple 2-step process that does not involve any php coding whatsoever. None. Zip. Nada. Zilch. All we need to do is upload the icons we want to use to our WordPress media library, and then futz with the CSS to get stuff looking awesome.

WordPress Custom Menu - Screenshot of icons in main menu

Step #1, uploading images, is the really easy part. Step #2, futzing with the CSS, can get a bit complicated. For example, if your theme uses gradient colors on menu items when you hover your mouse pointer over them, you’ll need to hunt down those style rules in your style-sheet ‘cuz we’re gonna need them. Unless, of course, you want to change that.

But, no worries, that’s what this tutorial is all about: to make it as simple as possible for you to just add the icons you want to the menu items you want. Why not just use a plugin? Simple really: one less plugin to update (if it gets updated); or break when WordPress updates; less server load too. Plus, plugins with icon functionality actually replace your current menu with a new style. This method simply works with your current design.

Before we begin, here’s a quick word about editing your style-sheet (I always add this to all my CSS tuts). There are 3 ways you can add custom CSS to your theme or child-theme (and use of a child-theme is highly recommended if you’re gonna be customizing anything!)

  • Add custom styles directly to the child-theme’s style.css file and upload via FTP.
  • Add them via the “Theme Editor” in your WordPress admin area.
  • Use the new “Custom CSS” panel added to Jetpack (gotta love it!)

If you’re handy with CSS and want to jump right in, scroll down to the end of this tutorial where you’ll see the full CSS required for 4 menu items with icons, including padding and CSS3 gradients on hover. Just copy/paste and play around. Ready? Let’s get started.

Upload some cool menu icons

Like I said, this is the easy part. Simply select the icons you want to use for your menu items, and upload them to your WordPress media library. Don’t have any good icons handy? One of the more popular sets is FamFamFam. Or visit Free Icons Web for over 30,000 of them!

Be sure that the icons you upload fit the existing dimensions of your menu items. For example, the navigation bar in Twenty-Eleven (WordPress default theme) has a height of 43pixels. So, anything from 16x16px to 24x24px is ideal. Once you’ve uploaded all your images, copy their File URLs to a blank text file and keep it handy.

Featured Plugin - WordPress Facebook Plugin

Would you like to add Facebook comments, registration, 'Like' buttons and autoposting to your WP site? Well, The Ultimate Facebook plugin has got that all covered!
Find out more

Identify the main nav container

In order to get individual icons to appear on individual menu items, we first need to identify the main navigation container. To do that, launch your browser’s developer tools. If you’re not sure how to do that, see “Tip #1″ in this post for help.

For the rest of this tutorial, and when required, I’ll be referencing stuff from the Twenty-Eleven (2011) theme ‘cuz everybody has it. But you should be able to follow along and adapt the required steps to your theme.

Got your developer tools open? Good. The ID or class of the main navigation container will differ from theme to theme. While it can be a div, a ul or in more recent themes a nav, and it can be called pretty much anything, it’s usually quite evident. In the 2011 theme, the main nav ID is nav#access as seen in the screenshot from Firebug below. To keep it handy, copy that ID – or class – to a text file (you can use the one you opened earlier for your image URLs).

WordPress Custom Menu - Screenshot of developer tools 1

Target individual menu items

Here’s where things have the potential to get a bit complicated. Why? Because we have a choice to make before we continue: there are 4 ways to target the individual menu items in our CSS, and each has its advantages and drawbacks. Let’s take a quick look at each method, find the best one for our needs, and then jump right in.

  1. li:nth-child(n). This method doesn’t really have any advantages for our purpose. It doesn’t work in older browsers. If you change the order of your menu items, or add a new item in between existing ones, you will need to edit your CSS to switch your icons around. So let’s not even bother with this one.
  2. li:first-child + li. Although this method does work in all browsers, it has the same major drawback as #1: if you change your menu in any way, you still need to switch the icons around. No good.
  3. Use the numerical class assigned automatically by WordPress to each menu item. The dual advantage of this method is that it works without fail in all browsers, and continues to work even if you change the order of your menu items, or add something new. The drawback is that it might create a security hole that could be exploited.
  4. Add our own class to each menu item in the menu editor. The advantages are the same as #3 above. Plus, it’s more secure because you get to choose the class name to assign to each item (ex: my-icon1, my-icon2…). Drawback: none. OK. So let’s use this method. (Post updated to use this method suggested by Nick Haskins. Props dude!)

So we’ll assign a unique class to each menu item we want to add an icon to. In your WordPress back-end, go to “Appearance” > “Menus”. On the first menu item you want to add an icon to, click it to open its options. If you don’t already see the option to add CSS classes, click the “Screen Options” tab at the top-right of your screen and tick the “CSS Classes” checkbox.

WordPress Custom Menu - Screenshot of custom menu editor

You can enter anything you like for your custom class for each menu item. Just be sure that it’s easily recognizable by you, and that the class name you choose is unique for each menu item. You could even use the menu item display name as its class but, if you do, be sure to use lowercase letters and replace any spaces with dashes. (Ex: myicon1, myicon2; about-us, our-mission). When you’re done, Save your menu.

OK. We’ve got the ID of the main nav container, and assigned a class to our 1st menu item. Now let’s get an icon in there, shall we? We want to add the icon as a background image to the link (the <a> tag) that sits inside the list item. So our CSS selector would be this:

#access .myicon1 a

…and the complete CSS to get a custom icon to display for this particular menu list item would be this:

#access .myicon1 a {
background:url('FULL-URL-TO-YOUR-UPLOADED-IMAGE-GOES-HERE') no-repeat 0.5em 0.5em #ffffff;
}

Copy the above code to your text file and, using the following breakdown, edit whatever needs editing for each of your menu items.

  • #access =The ID of your theme’s main nav container
  • .myicon1 = The class you assigned to your menu item
  • a = The link in the list item
  • url = The URL to your icon that you pasted earlier in a text file
  • no-repeat = Ensures that your icon does not tile and fill up the menu item
  • 0.5em 0.5em = If expressed in px, em, or %, it’s the distance of the icon from the left and the top of the list item (in that order). It can also be expressed as follows: left top, left center, left bottom, center top, center center, center bottom, right top, right center, right bottom. (If you only specify one value, the other will be set automatically to center, or 50%.)
  • #ffffff = The background color of the list item. This can also be set to transparent if you want the color of the main nav container to show through.

Once you have all your menu items defined as above, copy the whole shebang to your theme/child-theme’s style-sheet. If you have, say, 4 main items in your menu, your CSS could look like this:

#access .myicon1 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon2 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon3 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon4 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em transparent;
}

Save and/or upload your style-sheet. Then go refresh any page on your site. You should see your shiny new icons in each menu item you defined. Got ‘em? Cool, that wasn’t so hard. Ah, but they’re all scrunched up against the text in the links, aren’t they? So we need to adjust the padding of those links. Add the following to your style-sheet and refresh again (adjust this to fit the current padding values of your theme).

#access .myicon1 a, #access .myicon2 a, #access .myicon3 a, #access .myicon4 a {
padding:0 1.2125em 0 2.8em;
}

Next step: hover over any menu item. See the icon disappear? Now we need to define the CSS hover properties for those menu items.

Featured Plugin - WordPress Appointments Plugin

Take, set and manage appointments and client bookings without having to leave WordPress. Appointments+ makes it easy.
Find out more

Get stuff looking good on hover

This part isn’t really difficult at all ‘cuz we’ve already done all the hard stuff. To get things looking good on hover, we simply need to add a hover rule for each menu item. We need to add a rule for each item ‘cuz we need to call the background image (the icon) again. This is what that rule would look like for the 1st item in the sample menu:

#access .myicon1 a:hover, #access .myicon1 a:focus {
background:url('http://example.com/wp-content/uploads/2012/09/icon-30.png') no-repeat 0.5em 0.5em #efefef;
}

The only things that have changed in the hover rule are the addition of ‘:hover‘ to the ‘a‘ in the selector (plus a selector for ‘a:focus‘ which is pretty much the same thing), and the different background color of the link (change that to whatever color you wish to use). Go ahead and add a similar hover rule now for each of your menu items, and save/upload your style-sheet again. Refresh a page on your site and you should see the icons now appear even when you hover your mouse pointer over them.

Menus with CSS3 gradient colors

If the menu of your theme uses CSS3 gradient colors on hover, and you want to continue using those colors, you’ll need to do a bit of digging in your style-sheet, and modify a few things in the hover CSS we just wrote. You’ll first need to find the specific style rules for the background hover property of your main navigation links. Then, as each menu item now has a unique background image (icon), you need to add them to the background declaration of each menu item.

For example, looking through the style-sheet of 2011, we can see that the gradient hover rules for the background of the main menu items are as follows:

background: #f9f9f9; /* Show a solid color for older browsers */
background: -moz-linear-gradient(#f9f9f9, #e5e5e5);
background: -o-linear-gradient(#f9f9f9, #e5e5e5);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background: -webkit-linear-gradient(#f9f9f9, #e5e5e5);

You can see that there needs to be a distinct declaration for each browser type (CSS3 being relatively new to the browser-scape, there is as yet no uniformly accepted way to declare gradient colors). Here’s how to modify the background hover declarations we just wrote to include the CSS3 gradients in 2011:

#access .myicon1 a:hover, #access .myicon1 a:focus {
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em #efefef; /* Show a solid color for older browsers */
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -moz-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -o-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -webkit-linear-gradient(#f9f9f9, #e5e5e5);
}

As mentioned above, you’ll need to modify the hover properties of each menu item you added an icon to in order to get the gradient colors to display properly on hover.

Let’s end this with a full monty

Here’s the complete CSS for 4 menu items with icons, including required padding, and all the hover properties for CSS3 gradients from the 2011 theme. If you have more than 4 items, just copy/paste and play around with it. (Jeez. You could have skipped the whole tutorial and just scrolled down here for the goodies.)

#access .myicon1 a, #access .myicon2 a, #access .myicon3 a, #access .myicon4 a {
padding:0 1.2125em 0 2.8em;
}
#access .myicon1 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon2 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon3 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon4 a {
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em transparent;
}
#access .myicon1 a:hover, #access .myicon1 a:focus {
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em #efefef; /* Show a solid color for older browsers */
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -moz-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -o-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background:url('http://example.com/wp-content/uploads/2012/09/icon-1.png') no-repeat 0.5em 0.5em, -webkit-linear-gradient(#f9f9f9, #e5e5e5);
}
#access .myicon2 a:hover, #access .myicon2 a:focus {
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em #efefef; /* Show a solid color for older browsers */
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em, -moz-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em, -o-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em, -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background:url('http://example.com/wp-content/uploads/2012/09/icon-2.png') no-repeat 0.5em 0.5em, -webkit-linear-gradient(#f9f9f9, #e5e5e5);
}
#access .myicon3 a:hover, #access .myicon3 a:focus {
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em #efefef; /* Show a solid color for older browsers */
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em, -moz-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em, -o-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em, -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background:url('http://example.com/wp-content/uploads/2012/09/icon-3.png') no-repeat 0.5em 0.5em, -webkit-linear-gradient(#f9f9f9, #e5e5e5);
}
#access .myicon4 a:hover, #access .myicon4 a:focus {
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em #efefef; /* Show a solid color for older browsers */
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em, -moz-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em, -o-linear-gradient(#f9f9f9, #e5e5e5);
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em, -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background:url('http://example.com/wp-content/uploads/2012/09/icon-4.png') no-repeat 0.5em 0.5em, -webkit-linear-gradient(#f9f9f9, #e5e5e5);
}

I hope you enjoyed this tutorial, and find use for it. If you create something cool with it, please leave a comment with a link. If you need a hand with any part of it, ask away in the comments, and I’ll try to help you work things out. Thanks for reading!

Tags

Comments (15)

  1. Great write up, but here’s a better method.

    Apply a CSS class to the menu items using the, typically hidden by default, Menu CSS in Screen Options in Appearance—>Menus. Doing it this way, ensures you have icons next to new or changed menu items. The way you have it now, if the user changes their menu, the icons are gone.
    http://screencast.com/t/eSWFRKQr9K

    I realize this is a simple write up, not for l33t users, but IMO should never target the wp generated ID’s of menus unless its a personal site that will never go public.

    Nick

    • H1y4 N1ck,

      Gotta respect the opinion of anyone who knows l33tsp33k :)

      Thanks for the reminder about the CSS class option in the menu editor… had completely forgotten about that one :( It’s definitely an easier method of targeting specific menu items folks.

      Just to clear things up: using the method I outlined above, if the user changes the order of menu items, or adds new ones in-between, the icons will follow the changes. See http://www.screencast.com/t/mEXRMgTFyW

      However, if the user deletes a menu item, then decides to put it back in, you are right in stating that the icon will be gone, because the numerical class will have changed. So your method is better for that purpose.

      Question: could you enlighten readers on the security risk of using WP-generated IDs or classes?

    • Hiya Brad,

      Thanks for your input but, um, I think you missed the whole point of the tutorial: to make it as easy as possible for folks to add icons simply via CSS… without using any plugins.

      :o)

  2. Interesting idea. That CSS could be better – you’ve got loads of repeated stuff. You can’t avoid repeating the image URL in order to get the layers right (with the background image above the gradient), but you can eliminate repetition of the other background properties. How’s about:

    #access .myicon1 a:hover, #access .myicon1 a:focus {
    background-color: #efefef;
    background-repeat: no-repeat;
    background-position: 0.5em 0.5em
    background-image: url(‘http://example.com/wp-content/uploads/2012/09/icon-1.png’)
    background-image: url(‘http://example.com/wp-content/uploads/2012/09/icon-1.png’), -o-linear-gradient(#f9f9f9, #e5e5e5);
    background-image: url(‘http://example.com/wp-content/uploads/2012/09/icon-1.png’), -moz-linear-gradient(#f9f9f9, #e5e5e5);
    background-image: url(‘http://example.com/wp-content/uploads/2012/09/icon-1.png’), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5));
    background-image: url(‘http://example.com/wp-content/uploads/2012/09/icon-1.png’), -webkit-linear-gradient(#f9f9f9, #e5e5e5);
    }

    Other things to consider:
    1) Do you want the current, current parent or current ancestor menu items to be highlighted too? There are classes for that that could be included.
    2) Making a separate HTTP request for each icon isn’t very efficient. It would be good to use CSS sprites instead. There’s a neat trick for arranging CSS sprites to use as icons in this way that I’ve briefly written up here: http://oikos.org.uk/2012/04/tech-notes-css-sprites-for-list-elements/ – I use them for list element icons, but the same trick could be used for titles.

    Hope that adds a little extra!

    • Heya Ross,

      Thanks for the input! I love it when folks come by and streamline my stuff :)

      You’re also quite right about sprites being much more efficient, but this tut is oriented more toward those with little coding experience under their belts.

      The CSS is evidently required, but I wanted to keep it as simple as possible for folks, so they can just upload a few icons, pop a few lines into their style-sheet, and smile.

      Maybe I’ll do a follow-up to try and demystify sprites for newbies :)

  3. Good write up. I guess any way you shake it if you’re doing it for a client site there will have to be some info delivered on how to line up that class or icon.
    Im definitely all for sprites, especially with things like social media icons in menus, where they are less likely to change than a menu tab item. Cuts down on the http requests too. Nice post.

  4. Hi Patrick, thanks very much for the article. It was just what I was looking for and I already puzzled it out and used it in my theme. One important remark though:
    Like this it does not work right. You need to remove the # before the ‘#transparent’. Maybe you can change it in the article, cause it will save non-coders like myself a LOT of puzzling ;-)

  5. Thanks for this, it worked perfectly!

    Any idea how I would adjust it so that the icons sit on top of the text? Or is that not possible (perhaps custom click buttons aligned above would work for that? seems messy, though)?

    I also have an issue with spacing between the text; I have a line break in the titles in the navigation bars (they are long) and the gap between them is huge! I also have a big empty space to the right of each menu item, I’ve tried reducing padding and that’s not it, so I’m at a loss. One step forward, half a step back at the moment…

Participate