25

I would like to distribute a few list items horizontally on a bar, and I want to make the code modular so it automatically adjusts the space between items when I insert more.

I want the first item on the leftmost side, and the right item on the rightmost side, and the rest distributed in between. They all have equal space between each other. Think of separating a line segment into several pieces, the items would mark the points of separation, as well as the head/tail of the original line segment.

I tried several solutions and found some online, but they don't do what I want. They just centre everything more like putting each item in the middle of each line pieces according to my previous analogy.

Can someone please provide a nice solution in CSS?

Xavier_Ex
  • 8,432
  • 11
  • 39
  • 55
  • 1
    I'd say the answer is "with great difficulty". CSS is flat out terrible at distributing space between elements. (At least until the flexbox layout stuff becomes usable.) If you don't want your CSS to depend on the number of items, your obvious choices are: use tables, or just insert left-to-right with some padding. – millimoose Nov 22 '12 at 03:51
  • 2
    I am not sure that is reasonably possible with only CSS--I have only ever done things like that by resorting to JavaScript adjustment of widths. Tables might help, but they are often considered bad form these days when used for anything other than tabular data. – SAJ14SAJ Nov 22 '12 at 03:56

4 Answers4

29

You can do what you are after using inline-block, pseudo-elements and text-align: justify;, but it will only work in IE8 and above.

Here is the code:

<!-- HTML -->

<ul>
    <li>List Item 1</li>
    <li>List Item 2</li>
    <li>List Item 3</li>
    <li>List Item 4</li>
</ul>

​
/* CSS */

ul {
    text-align: justify;
}
ul:after {
    content: '';
    display: inline-block;
    width: 100%;
}
ul:before {
    content: '';
    display: block;
    margin-top: -1.25em;
}
li {
    display: inline-block;
    margin-right: -.25em;
    position: relative;
    top: 1.25em;
}

Live demo: http://jsfiddle.net/joshnh/UX9GU/

joshnh
  • 8,374
  • 4
  • 35
  • 53
  • I tried it out and it worked, but can you please explain the magic here? – Xavier_Ex Nov 22 '12 at 19:06
  • 4
    The answer to this question does a good job of explaining it: http://stackoverflow.com/questions/11589590/text-align-justify-inline-block-elements-properly – joshnh Nov 22 '12 at 21:14
9

There is an clean solution:

http://radiatingstar.com/distribute-divs-images-equaly-line

#container {
    text-align: justify;
}
#container > div {
    width: 100px; /* Declare your value. Can be in relative units. */
    display: inline-block;
    vertical-align: top;
}
#container:after {
    content: "";
    width: 100%;
    display: inline-block;
}
Marcelo Amorim
  • 1,662
  • 23
  • 23
7

As an addition to joshnh answer, if anyone has the same issue:

Watch out: text-align: justify; needs a space after every display: inline-block; element to work. Otherwise the elements are treated as one word and will not distribute horizontally.

So this won't work:

<!-- HTML -->
<ul><li>Item 1<li><li>Item 2<li><li>Item 3<li><li>Item 4<li></ul>

But this will:

<!-- HTML -->
<ul>
  <li>Item 1<li>
  <li>Item 2<li>
  <li>Item 3<li>
  <li>Item 4<li>
</ul>

I just had this issue because we are minifying our HTML-Markup and the minifier puts everything in one line.

Zwergal
  • 71
  • 1
  • 3
5

In 2019 there is a flex solution for it with justify-content: space-between

<ul>
  <li>Item 1<li>
  <li>Item 2<li>
  <li>Item 3<li>
  <li>Item 4<li>
</ul>
ul {
  width: 100%; /* Your element needs a fixed width */
  display: flex;
  justify-content: space-between;
}
neiya
  • 2,657
  • 4
  • 23
  • 32