htmlcssnavigationjustify

How to stretch a fixed number of horizontal navigation items evenly and fully across a specified container


I'd like to stretch 6 nav items evenly across a 900px container, with an even amount of white space between. For instance...

---| 900px Container |---

---| HOME    ABOUT    BASIC SERVICES    SPECIALTY SERVICES    OUR STAFF    CONTACT US |---

Currently, the best method I can find to do this is the following:

nav ul {
  width: 900px; 
  margin: 0 auto;
}

nav li {
  line-height: 87px;
  float: left;
  text-align: center;
  width: 150px;
}

The PROBLEM with this is two fold. First of all, it doesn't truly justify it, but rather spreads the li tags evenly throughout the ul tag.. creating uneven white-space between smaller menu items like "HOME" or "ABOUT" and larger ones like "BASIC SERVICES".

The second problem is that the layout breaks if a nav item is larger than 150px, which SPECIALTY SERVICES is - even though there is more than enough space for the whole nav.

Can anyone solve this for me? I've been scouring the web for solutions, and they all seem to come up short. CSS / HTML only if possible...

Thanks!

UPDATE (7/29/13): Using table-cell is the best modern way to implement this layout. See felix's answer below. The table cell property works on 94% of browsers currently. You'll have to do something about IE7 and below, but otherwise should be ok.

UPDATE (7/30/13): Unfortunately, there is a webkit bug that impacts this if you're combining this layout with Media Queries. For now you'll have to avoid changing the 'display' property. See Webkit Bug.

UPDATE (7/25/14): There is a better solution to this below now involving text-align: justify. Using this is simpler and you'll avoid the Webkit bug.


Solution

  • The modern way to distribute items evenly is to set the following two declarations on the container element:

    .container {
      display: flex; /* (1) */
      justify-content: space-between; /* (2) or space-around or space-evenly */ 
    } 
    

    The value to use for justify-content depends on which kind of even distribution is needed.

    enter image description here

    See MDN

    ul {
      list-style: none;
      padding: 0;
      width: 90vw;
      border: 3px solid gold;
      display: flex;
    }
    a {
      background: gold;
    }
    ul {
      justify-content: space-between;
    }
    ul ~ ul {
      justify-content: space-around;
    }
    ul ~ ul ~ ul {
      justify-content: space-evenly;
    }
    <h3>justify-content: space-between; </h3>
    
    <ul id="nav">
      <li><a href="#">HOME</a></li>
      <li><a href="#">ABOUT</a></li>
      <li><a href="#">BASIC SERVICES</a></li>
      <li><a href="#">OUR STAFF</a></li>
      <li><a href="#">CONTACT US</a></li>
    </ul>
    <div>Distributes items evenly. The first item is flush with the start, the last is flush with the end </div>
    <hr>
    <h3>justify-content: space-around;</h3>
    <ul id="nav">
      <li><a href="#">HOME</a></li>
      <li><a href="#">ABOUT</a></li>
      <li><a href="#">BASIC SERVICES</a></li>
      <li><a href="#">OUR STAFF</a></li>
      <li><a href="#">CONTACT US</a></li>
    </ul>
    <div>Distribute items evenly. Items have a half-size space on either end</div>
    <hr>
    <h3>justify-content: space-evenly;</h3>
    <ul id="nav">
      <li><a href="#">HOME</a></li>
      <li><a href="#">ABOUT</a></li>
      <li><a href="#">BASIC SERVICES</a></li>
      <li><a href="#">OUR STAFF</a></li>
      <li><a href="#">CONTACT US</a></li>
    </ul>
    <div>Distribute items evenly. Items have equal space around them</div>
    <hr>


    Here's my original answer - if for some reason using a flex container isn't viable

    Use text-align:justify on the container, this way it will work no matter how many elements you have in your list (you don't have to work out % widths for each list item

        #nav {
            text-align: justify;
            min-width: 500px;
        }
        #nav:after {
            content: '';
            display: inline-block;
            width: 100%;
        }
        #nav li {
            display: inline-block;
        }
    <ul id="nav">
        <li><a href="#">HOME</a></li>
        <li><a href="#">ABOUT</a></li>
        <li><a href="#">BASIC SERVICES</a></li>
        <li><a href="#">OUR STAFF</a></li>
        <li><a href="#">CONTACT US</a></li>
    </ul>

    FIDDLE