99

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;
}
2
  • 1
    <span> isn't block element, it shouldn't accept width property Commented Aug 30, 2011 at 14:43
  • Can you provide the actual code? Commented Aug 30, 2011 at 14:46

10 Answers 10

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;
}
3
  • 3
    With this method, the cells are not evenly distributed. See jsfiddle.net/hcrzx. The middle cell is longer than the other two cells.
    – Susam Pal
    Commented Jul 6, 2013 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
    Commented Jul 7, 2013 at 20:34
  • Note: The distribution is not completely even because the left and right paddings are half of those in-between contents.
    – EvgenKo423
    Commented May 8 at 12:08
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

0
31

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/

1
  • that was the droid I was looking for! Thank you. Commented Jan 22, 2022 at 21:54
11

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

1
  • Cool answer. Tip: Use flex-wrap: wrap to wrap the content around. Commented Sep 26, 2019 at 12:10
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/

7
  • 2
    sooo... there is no easy way for it to just automatically adjust the width?
    – jurchiks
    Commented Aug 30, 2011 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
    Commented Aug 30, 2011 at 14:57
  • right @Shauna. @jurchiks, you could auto calculate the widths based on the number of spans but that would require some js. If your menu is not changing frequently, adjusting the width should not be a problem. Commented Aug 30, 2011 at 14:58
  • @josh.trow. It has been slow for me all day. Commented Aug 30, 2011 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
    Commented Aug 30, 2011 at 15:09
5

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

#menu{
    width: 800px;
    display: flex;
    justify-content: space-between;
}
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>

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>
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 :-)

Not the answer you're looking for? Browse other questions tagged or ask your own question.