Grow your CSS skills. Land your dream job.

Centering List Items Horizontally (Slightly Trickier Than You Might Think)

Published by Chris Coyier

Update April 2013: This article is pretty old. This isn't very hard. Just give the list centered text (e.g. ul.nav { text-align: center; }) and the list items inline-block (e.g. ul.nav li { display: inline-block; }). If you want to do it with margin for whatever reason, look into width: fit-content; (link).

The current standard in coding menus is unordered lists. It's not as semantic as a <nav> tag would be, but it's not that bad. Navigation is, after all, a list of sorts.

If you want to make this navigational unordered list horizontal, you have basically two options:

  • Make the list items inline instead of the default block. .li { display: inline; } This will not force breaks after the list items and they will line up horizontally as far as they are able.
  • Float the list items. Since we very often want our list items to display as blocks so we are able to set fixed widths on them, we are forced to float them to the left or right to line them up horizontally.

Now let's make a couple common decisions about how we want to display this menu:

  • We want the menu to be centered. Doesn't matter if the menu is in a fixed or fluid width environment, we just want the menu elements to be centered in the parent element
  • The menu will be a horizontal bar, so we want to make sure that bar looks visually like a bar. We would like to use a repeating background image for this.

Now we are in trouble. The <ul> itself can't be in charge of the background image, because it will only be as wide as it needs to be to help with centering. So we put it inside of a div at 100% width to to take care of the background image. But now our little centering trick doesn't work. To be honest I'm not exactly sure why, but applying .ul {margin: 0 auto;} just doesn't work here. This is where the trick comes in...

Wrap the list inside a table div

If we wrap the menu in a "table" div, we can solve this. If you are familiar with Stu Nicholls from CSSPlay, he uses this all the time on his awesome horizontal menus. Check out the HTML:

<div id="menu-outer">
  <div class="table">
    <ul id="horizontal-list">
      <li><a href="#"><img src="images/list-item-1.gif" alt="list item 1" /></a></li>
      <li><a href="#"><img src="images/list-item-2.gif" alt="list item 2" /></a></li>
      <li><a href="#"><img src="images/list-item-3.gif" alt="list item 3" /></a></li>
      <li><a href="#"><img src="images/list-item-4.gif" alt="list item 4" /></a></li>
    </ul>
  </div>
</div>

Now see the very simple CSS that makes it happen:

#menu-outer {
	height: 84px;
	background: url(images/bar-bg.jpg) repeat-x;
}

.table {
	display: table;   /* Allow the centering to work */
	margin: 0 auto;
}

ul#horizontal-list {
	min-width: 696px;
	list-style: none;
	padding-top: 20px;
	}
	ul#horizontal-list li {
		display: inline;
	}

It's the table div that get the job done. Some days I think "Whatever works." should be the slogan for CSS.

View Demo   Download Files

Comments

  1. Permalink to comment#

    It not work in IE7.

    Change the

    ul#horizontal-list li {
    float: left;
    }

    to

    ul#horizontal-list li {
    display:inline
    }

    It’s well.

    But when the li element is not img.
    It is not the best.

  2. @Mogly: Yep, you are right. IE doesn’t like it when it’s floated. Weird. I have updated the article to reflect the change. Perhaps if the list items were text and not images it might not be quite as clean, but I still think it would be alright. Just so long as you applied enough spacing between the menu elements. At least they would still be centered.

  3. One question Chris — why do you need to use lists for this? Why not simply float the images next to each other?

    I ask because I see lists everywhere and I just don’t see a need for them in navigation. Why can’t programmers simply use “{ display:block; }”?

    Take my site for example: http://davidwalsh.name

    If you look at the navigation code, it’s just a div with a bunch of anchor tags — no lists. It was a huge pain to get rid of the unnecessary lists in WordPress. Lists, in the case of navigation, can be a real waste of bandwidth.

  4. Permalink to comment#

    Er… for my contact bar I just did

    ul.contact { width: 100%; text-align: center; }

    and

    ul.contact li { display: inline; }

    and that was it. Am I missing something? Of course, as it is now if there are too many items in the list they’ll start to wrap.

    Iit’s at http://robertobaca.com the one at the bottom (for some reason I didn’t do this for the main nav, guess it didn’t occur to me then)

  5. @David Walsh: There are a lot of reasons to use a list. For one, it’s nice to the wrap the menu in something so you have some positioning possibilities. A <ul> with a unique ID just seems to fit the bill a lot of times. On your site it looks like you wrapped it inside a DIV. With a list you get both <li> elements and anchor elements to style, which gives you some extra options. You might not need them all today, but it’s nice to have the control for a redesign idea you might have tomorrow.

    @Roberto: Yeah this is starting to get a little confusing… Let’s say you wanted to declare an absolute width to each of those list items in your contact bar, a reasonable request. You would need to use block level elements instead of inline elements to do that. Now the text-align property isn’t going to help, because you’ll have to float them to the left. Now you won’t be able to keep them centered because of that left float.

    That was the original intention of my article, solving that problem. But now it seems my original solution isn’t IE friendly, for some strange reason, so I updated to utilize the display: inline idea. That works, but if I do that… then your solution works just as well.

    So you can see, this is starting to lose focus a little bit =P

  6. Permalink to comment#

    I see. I know that feeling :)

    Thanks!

  7. stefan eder
    Permalink to comment#

    @david walsh: I had a look at your code and have to say it doesn´t look very good in terms of website accessibility. Using lists for navigation makes for me a lot of sense when you consider this point.

  8. @Stefan: Accessibility-wise? How so? With adding javascript libraries to my site (as do most sites), I prefer not to use unnecessary code (in the form of UL, OL, and LI’s).

  9. stefan eder
    Permalink to comment#

    @David: I made good experiences with using lists for Accessibility. But i must admit it´s not a necessary code, the navigation also works without lists. It´s just a point of view.

  10. I think perhaps stefan is saying that with CSS turned off (screen-reader-style), menus that use the unordered list technique revert to a regular looking list (with bullets) which is a pretty nice way to degrade.

  11. I see your point now — I’ll keep that in Mind for CSS Naked Day. Until then, I’ll continue my crusade against navigation lists.

  12. @David: That’s fine by me ;-)

  13. Personally have not seen the display: table; used before…
    Sounds useful!

    @David – along with the css turn off point that Chris pointed out, I would also suggest it is more semantic than other suggestions as with a lot of navigations, all you would require is the ul and li and it saves using other divs etc.

  14. Permalink to comment#

    You make me really easy. Thanks. Can you help me that i sometimes when i make few id floating it goes down under . Don’t know what happens there . please help me.

  15. @Prap: If you have floated items, and the parent element become too small in width to contain them side by side, it will push them “down under”. To prevent this, just make sure the parent element cannot become to small where this happens by either setting a static width that is large enough, or a min-width.

  16. Permalink to comment#

    Hi PraP

    to prevent the *down under* I’m using

    white-space nowrap .

    If someone using font size +++++ there is a horizontal scrollbar, but he can read the content.

    Maybe not the perfect solution for this problem but I know if someone needs font-size +++++ he is using a screenreader most of the time.

    Or he knows that there is a horizontal scrollbar most of the time.

    regards
    Monika

  17. Autocrat
    Permalink to comment#

    Okay… I’m tackling something similar… but attempting to cover all bases and ensure widest usage, which is failing (it seems that css has a minor flaw, you can do A, B or C fine… it’s when you want to do A and B that it gets difficult).

    So the aim; to use a standard list to hold text-based links, and generate a horizontal bar.
    From there, center the bar so that links appear in the middle.
    Make all the links a set width, in EM.
    Permit the “link height” to increase as needed (text will wrap).
    If their are too many links in a row, or the width is shortened, then things should drop down to the line below, and continue doing so.

    This means that no matter the width, the contents of the menu will always be centered and visible.
    Text based means slightly better SEO and Accessibility as well.
    The EM width setup means altering text-size permits scaling, better accessibility.
    Permitting flexible height means that we can avoid worrying about over long link titles (3 or 4 words), as the menu will accomodate.

    The problem is, I simply fail when attempting this.
    The closes I can get is using tabe/t-row/t-cell (anyone noticed if you set display:block, then display: table… IE6 seems to respond to the table?)… yet that alters the behaviour drastically and/or puts a gap infront of each list item.

    So, if anyone has succeeded at this, or fancies playing, let me know :)

    Also, Happy Christmas folks (for those that celebrate it).

  18. @Autocrat: Here is a crack at your problem:

    http://css-tricks.com/examples/CenteredTextLinks/

    It seems to work OK, but it exhibits some semi-weird behavior. For example, in FF when you expand to the point a link box wraps down to the next line, it works fine, but when you decrease the size back down, it doesn’t un-wrap back up. Weird, but probably not that big of a deal.

  19. LukeR
    Permalink to comment#

    Hi Chris, your code seems to work in Opera, Safari and Firefox but neither IE6 or 7 seem to like it, not sure if its an issue with my code but im rather desperate to get this working! any help would be greatly appreciated. I dont have a “menu-outer” div, just the table wrap div. i am also using Joomla 1.5, so the list items are generated rather than hard coded.

    #listwrap {
    display: table; /* Allow the centering to work */
    margin: 0 auto;
    }
    #topmenu {
    height:40px;
    }
    #topmenu ul.menu {
    min-width: 40px; /* to account for 1 - 2 list items */
    list-style: none;
    }
    #topmenu li {
    display: inline;
    }

    Thanks in advance for any comments or help anyone can give.

  20. @LukeR: Do you have a URL we can look at to see the problem? Is the centering what you are having trouble with, or something else? For starters, IE probably won’t obey that min-width so you may need to do something else there.

  21. LukeR
    Permalink to comment#

    Cheers for the quick response Chris, ive just made my tempalte viewable live at

    http://www.nukedesign.co.uk/dev/sitetest/

    Tryed using a min-width hack for ie6/7, (yours actually!) but that dosnt seem to crack it either.


    #topmenu ul.menu {
    min-width: 40px;
    max-width:880px;
    width:expression(document.body.clientWidth 882? "880px" : "auto");
    list-style: none;
    }

    As you can see it works fine in every browser non-ie based.
    Im also having problems with the mootools in everything but Safari and FF, but thats not your area ;)

    Thanks again for any help you can give.

    Luke

  22. @LukeR: Yeah I can see the menu isn’t centered in IE6. It’s just off to the left though, doesn’t look too awful. For this type of menu, you might wanna just consider ditching the unordered list and going with a series of anchor links. That way you can just have a wrapping div and set the text-align to center and it will work just fine.

  23. LukeR
    Permalink to comment#

    Cheers for that Chris, unfortunately this is going to be a joomla template, the UL’s are generated by joomla so not much i can do there, guess il have to go for a new look! thanks for all your help!

    Best Regards,
    Luke

    • Raf
      Permalink to comment#

      This Css hack worked perfectly for me on FF3 and IE7, not yet tested in IE6 but I will. However I had to do some additional tweaks in order to make it centered in IE7, as I did had similar problem like LukeR.

      Here is what I have done:

      #menu-outer {
      height: 84px;
      }

      .hortable {
      display: table; /* Allow the centering to work */
      margin: 0 auto;

      }

      ul#horizontal-list
      {
      min-width: 50px;
      list-style: none;
      text-align:center; /* This is the tweak i made */

      }
      ul#horizontal-list li {
      display: inline;
      }

  24. Stevie D
    Permalink to comment#

    This seems a very complicated way of going about things. I have a centred nav bar on one of my sites, and all I’ve done is

    ul#menu {text-align:center; list-style-type:none;}
    ul#menu li {display:inline;}

    Obviously there’s a bit more styling than that, but that seems to do the trick of lining it up with the middle of the page.

  25. I know jake diddly about css, I just wanted to say I really love your backround page of travel luggage tags and that it could be used as a my space layout for people to download, personalize and upload to their little profiles…I know I would.
    That’s it. I found your site on a search while looking for a myspace menu I created in my mind and went looking for a something close.
    Thanks for the time to read this.
    Critter

  26. _megankish__
    Permalink to comment#

    Hello,

    I’m having some trouble implementing your centered li. I’m assuming my issue is that I’m not using text, but BG images for each li. Let me explain:

    I’m working on a site that will eventually have dynamically driven navigation (via back-end editing). I’ve been using the following code as a standard for my nav, and it’s worked famously:

    <div id="navcontainer">
    <ul>
    <li class="navexample01"><a href="#"></a></li>
    <li class="navexample02"><a href="#"></a></li>
    <li class="navexample03"><a href="#"></a></li>
    <li class="navexample04"><a href="#"></a></li>
    </ul>

    With this code I attached the following CSS (generalized):

    #navcontainer ul {
    display:block;
    background-image: url(images/example.jpg);
    background-repeat: no-repeat;
    background-position: left top;
    }

    .navexample01 a {
    background-image: url(images/exampleoff.jpg);
    background-repeat: no-repeat;
    background-position: left top;
    display: inline-block;
    float: left;
    width: 50px;
    height: 25px;
    }

    .navexample01 a:hover {
    background-image: url(images/exampleon.jpg);
    background-repeat: no-repeat;
    background-position: left top;
    display: inline-block;
    float: left;
    width: 50px;
    height: 25px;
    }

    So on and so forth. I give each class it’s own background image as well as hover image. Most of the time each button has a different width which is why i can’t do a general sizing for all li. I use a BG image on the UL itself to avoid the “flicker” effect that IE6 gives to rollovers.

    At any rate, I know that I can’t use the float left to get the list items to appear centered. But if I don’t use [the float] it doesn’t show up!

    YOU’RE HELP WOULD BE GREATLY APPRECIATED!

  27. _megankish__
    Permalink to comment#

    Ugh, I just realized I used you’re instead of your. STUPID TYPO! ;)

  28. _megankish__
    Permalink to comment#

    It only took me 1/2 the day, but I figured it out! WOOT! I’m not even sure if someone posted the answer, but somehow, I manged to get this to work, cross browser! YAY!

    I cannot post my results as I am under a strict deadline for this particular project! If you’d like me to post my results, I can most certainly do so upon request!

    THANKS FOR ALL THE GREAT IDEAS! I used partial bits of your css trickery to get this to work! :D

  29. Still a useful article 6 years later !

  30. Permalink to comment#

    Cheers! Love how CSS-Tricks ranks so well against Stackoverflow lately… keep up the good work Chris, I’ll buy you a beer 1 day!

  31. Patrik
    Permalink to comment#

    Ugh, using tables I see. Horrible! >:( This solution is not cross browser friendly.

  32. ibrahim
    Permalink to comment#

    how would you do it if you were using display:block and not display:inline.

  33. Eric Andrew Lewis
    Permalink to comment#

    A problem with using display: inline on your list items is that, since they’re inline elements, the white space in-between the elements will translate to a space the width of a regular space of the font. This is imperceivable in some designs, but when you have say a border in between elements, things get hairy.

    To combat this, a few options.

    You can set font-size:0 on the

    <

    ul>, and font-size: whatever on the , so the gap will be rendered as 0 pixels wide.

    You can take out all the white space in the HTML between the s.

  34. Mr Bear
    Permalink to comment#

    your css code worked for the drop down menus I wanted to center but when I added images to be at the top of the page the menu got put back on the left again, what did I do wrong?

  35. It seems we can´t get rid of tables at all. Nice trick, it worked with the site I am developing. Never saw that before, very clean solution!

  36. Khagesh

    perfect (Y)

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".