98

This is meant for a menu.
For example I have a div element with 3 spans in it, all of which have some margin, max-width and float (left or right).
It is positioned starting from the left side and goes like this:
[[span1][span2][span3] - lots of free space here].
I want to make it even out like this:
[[span1] - space - [span2] - space - [span3]]
How can I do this using CSS? I kinda doubt it is not possible.
Note that I want it to keep the same style when I add or remove a menu item.
HTML:

<div id="menu">
    <span class="menuitem"></span>
    <span class="menuitem"></span>
    <span class="menuitem"></span>
</div>

CSS:

#menu {
    ...
    width:800px;
}
.menuitem {
    display:block;
    float:left;
    margin-left:25px;
    position:relative;
    min-height:35px;
    max-width:125px;
    padding-bottom:10px;
    text-align:center;
}
jurchiks
  • 1,081
  • 1
  • 8
  • 4

10 Answers10

108

In the 'old days' you'd use a table and your menu items would be evenly spaced without having to explicitly state the width for the number of items.

If it wasn't for IE 6 and 7 (if that is of concern) then you can do the same in CSS.

<div class="demo">
    <span>Span 1</span>
    <span>Span 2</span>
    <span>Span 3</span>
</div>

CSS:

div.demo {
    display: table;
    width: 100%;
    table-layout: fixed;    /* For cells of equal size */
}
div.demo span {
    display: table-cell;
    text-align: center;
}

Without having to adjust for the number of items.

Example without table-layout:fixed - the cells are evenly distributed across the full width, but they are not necessarily of equal size since their width is determined by their contents.

Example with table-layout:fixed - the cells are of equal size, regardless of their contents. (Thanks to @DavidHerse in comments for this addition.)

If you want the first and last menu elements to be left and right justified, then you can add the following CSS:

div.demo span:first-child {
    text-align: left;
}
div.demo span:last-child {
    text-align: right;
}
MrWhite
  • 43,179
  • 8
  • 60
  • 84
  • 3
    With this method, the cells are not evenly distributed. See http://jsfiddle.net/hcrzx/. The middle cell is longer than the other two cells. – Susam Pal Jul 06 '13 at 18:35
  • 1
    @Susam: True, the cells are not necessarily of _equal size_, since the width of the cell is determined by its contents (the same as with an HTML table). However, I would still say they can be described as _evenly distributed_, since they are evenly distributed (not necessarily equally) across the full width of the parent element, based on their contents. If you want cells of equal size, regardless of their contents, then I'd wager you'd need a scripted solution. – MrWhite Jul 07 '13 at 20:34
52

You can use justify.

This is similar to the other answers, except that the left and rightmost elements will be at the edges instead of being equally spaced - [a...b...c instead of .a..b..c.]

<div class="menu">
    <span>1</span>
    <span>2</span>
    <span>3</span>
</div>

<style>
.menu {text-align:justify;}
.menu:after { content:' '; display:inline-block; width: 100%; height: 0 }
.menu > span {display:inline-block} 
</style>

One gotcha is that you must leave spaces in between each element. [See the fiddle.]

There are two reasons to set the menu items to inline-block:

  1. If the element is by default a block level item (such as an <li>) the display must be set to inline or inline-block to stay in the same line.
  2. If the element has more than one word (<span>click here</span>), each word will be distributed evenly when set to inline, but only the elements will be distributed when set to inline-block.

See the JSFiddle

EDIT:
Now that flexbox has wide support (all non-IE, and IE 10+), there is a "better way".
Assuming the same element structure as above, all you need is:

<style>
    .menu { display: flex; justify-content: space-between; }
</style>

If you want the outer elements to be spaced as well, just switch space-between to space-around.
See the JSFiddle

SamGoody
  • 13,758
  • 9
  • 81
  • 91
30

If someone wants to try a slightly different approach, they can use FLEX.

HTML

<div class="test">
    <div>Div 1</div>
    <div>Div 2</div>
    <div>Div 3</div>
    <div>Div 4</div>
</div>

CSS

.test {
    display: flex;
    flex-flow: row wrap;
    justify-content: space-around;
}
.test > div {
    margin-top: 10px;
    padding: 20px;
    background-color: #FF0000;
}

Here is the fiddle: http://jsfiddle.net/ynemh3c2/ (Try adding/removing divs as well)

Here is where I learned about this: https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Pratul Sanwal
  • 544
  • 7
  • 9
10

justify-content: space-betweenanddisplay: flex is all we needed, but thanks to @Pratul for the inspiration!

Crashalot
  • 33,605
  • 61
  • 269
  • 439
8

This is the quick and easy way to do it

<div>
    <span>Span 1</span>
    <span>Span 2</span>
    <span>Span 3</span>
</div>

css

div{
    width:100%;
}
span{
    display:inline-block;    
    width:33%;
    text-align:center;
}

Then adjust the width of the spans for the number you have.

Example: http://jsfiddle.net/jasongennaro/wvJxD/

Jason Gennaro
  • 34,535
  • 8
  • 65
  • 86
  • 2
    sooo... there is no easy way for it to just automatically adjust the width? – jurchiks Aug 30 '11 at 14:51
  • `width: 33%;` is about as close as you can get, but it's based off of the parent container, not the number of child elements. If you want it to adjust based off of the child (span) elements, you'll probably need to play with JavaScript. – Shauna Aug 30 '11 at 14:57
  • right @Shauna. @jurchiks, you could auto calculate the `width`s based on the number of `span`s but that would require some js. If your menu is not changing frequently, adjusting the `width` should not be a problem. – Jason Gennaro Aug 30 '11 at 14:58
  • @josh.trow. It has been slow for me all day. – Jason Gennaro Aug 30 '11 at 14:59
  • @Jason - done that already (except in PHP; don't know JS good enough, maybe someone can teach me how to do this?). Looks fine, but margins become a problem. – jurchiks Aug 30 '11 at 15:09
  • Sure @jurchiks. You will need to adjust the `width`s to incorporate the `margin`s. So, if you have a `margin:1%` on either side (as an example), then you need to make `width:31%`. – Jason Gennaro Aug 30 '11 at 15:11
  • consider giving the outer tag a `display: table`, the inner a `display:table-cell` (does not at have to be ``, `
    `) and give `table-layout` (i.e: fixed) a good look...
    – Frank N Mar 30 '17 at 10:56
4

You just need to display the div with id #menu as flex container like this:

#menu{
    width: 800px;
    display: flex;
    justify-content: space-between;
}
AzafoCossa
  • 874
  • 8
  • 18
1

.container {
  padding: 10px;
}
.parent {
  width: 100%;
  background: #7b7b7b;
  display: flex;
  justify-content: space-between;
  height: 4px;
}
.child {
  color: #fff;
  background: green;
  padding: 10px 10px;
  border-radius: 50%;
  position: relative;
  top: -8px;
}
<div class="container">
  <div class="parent">
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
    <span class="child"></span>
  </div>
</div>
Dipak
  • 6,532
  • 8
  • 63
  • 87
0

Make all spans used inline-block elements. Create an empty stretch span with a 100% width beneath the list of spans containing the menu items. Next make the div containing the spans text-align: justified. This would then force the inline-block elements [your menu items] to evenly distribute.

https://jsfiddle.net/freedawirl/bh0eadzz/3/

  <div id="container">

          <div class="social">
            <a href="#" target="_blank" aria-label="facebook-link">
            <img src="http://placehold.it/40x40">
            </a>
            <a href="#" target="_blank" aria-label="twitter-link">
                <img src="http://placehold.it/40x40">
            </a>
            <a href="#" target="_blank" aria-label="youtube-link">
                <img src="http://placehold.it/40x40">
            </a>
            <a href="#" target="_blank" aria-label="pinterest-link">
                 <img src="http://placehold.it/40x40">
            </a>
            <a href="#" target="_blank" aria-label="snapchat-link">
                <img src="http://placehold.it/40x40">
            </a>
            <a href="#" target="_blank" aria-label="blog-link">
                 <img src="http://placehold.it/40x40">
            </a>

            <a href="#" aria-label="phone-link">
                 <img src="http://placehold.it/40x40">
            </a>
            <span class="stretch"></span>
          </div>
             </div>
freedawirl
  • 19
  • 3
0

I have managed to do it with the following css combination:

text-align: justify;
text-align-last: justify;
text-justify: inter-word;
0

I wanted the children to fill the container space evenly with a small gap around the edge, so I found this worked best:

#menu {
    display: flex;
    flex-flow: row nowrap;
    gap: 5px;
    background-color: #00FF00;
    padding: 10px 0;
}

.menuitem {
    background-color: #FF0000;
    flex-grow: 1;
    text-align: center;
}

Strong colors added just to show you the effect of the spacing and borders :-)

SharpC
  • 6,974
  • 4
  • 45
  • 40