31

Is it possible to evenly space many elements in a div with changeable width.

Here's not working example. If we use text-align:center; elements will be centered, but margin:0 auto; is not working. I want to accomplish something like justify+center:

|..<elem>..<elem>..<elem>..<elem>..|       // for one container width
|..<elem>..<elem>..<elem>..|               // for smaller container width
|....<elem>....<elem>....|                 // even smaller container

Container will be user resizable. One picture is worth a 1000 words:

enter image description here

Container(red box) width:100%; So user can resize it (browser window, js, whatever).
<--> represent even spaces. In second row <--> are bigger because there is more room. I was able to fake it with:

text-align:center;
word-spacing:3em;    // but any fixed value looses proportion
CoR
  • 3,826
  • 5
  • 35
  • 42
  • possible duplicate of [Equal spacing div's in a container](http://stackoverflow.com/questions/15140402/equal-spacing-divs-in-a-container) – Aurelio De Rosa Jun 06 '13 at 14:11
  • This might also help you : http://stackoverflow.com/questions/16613047/smart-fluid-javascript-navigation-helper/16613446#16613446 – Brewal Jun 06 '13 at 14:15
  • This may also be of interest to you: CSS flexible boxes https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes – rink.attendant.6 Jun 06 '13 at 15:04
  • @ rink.attendant.6: yes, that picture is exactly what I want. elements are the same size, all margins shrink evenly. if there's no space margins will expand but elements will be centered. – CoR Jun 06 '13 at 15:27
  • @CoR - the picture makes it a lot clearer what you're trying to achieve. I have a feeling you might find it tricky to do. I'd be very interested to see a solution. – Spudley Jun 06 '13 at 19:35
  • @Spudley: I am sorry I didn't made that picture earlier. Your solution is very near of what I want, yet very far in some way. I hope there is a relatively simple solution. If not, I'll use your answer with custom padding. Thank you for all your help :) – CoR Jun 06 '13 at 19:56
  • 1
    @CoR - I've added an edit to my answer with a few final thoughts. – Spudley Jun 06 '13 at 20:09

3 Answers3

41

I recently read about a very clever technique to do exactly what you're asking.

In short, you just need to use text-align:justify; on the container element to achieve this, in conjunction with an extra invisible block at the end.

This works because inline-block elements are seen as being part of the text content, each being effectively a single word.

Using justify will spread out the words in your text so that they fill the entire width of the element with extra space between the words. For inline-block elements, this means that they are spaced out with even spaces between them.

I mentioned an extra invisible block at the end. This is required because normal text-align:justify won't justify the last line of text. For normal text, that's exactly what you want, but for aligning inline-block boxes, you want them all to be aligned.

The solution is to add an extra invisible but 100% width element to the end of your list of inline-block elements. This will become effectively the last line of text, and thus the justify technique will work for the rest of your blocks.

You can use the :after pseudo-selector to create the invisible element without needing to modify your markup.

Here's an updated version of your jsFiddle to demonstrate: http://jsfiddle.net/ULQwf/298/

And here's the original article that explains it in more detail: http://www.barrelny.com/blog/text-align-justify-and-rwd/

[EDIT] One final update after seeing the image you've added to the question. (I don't have a better answer, but some additional thoughts that might be useful).

Ideally what you need here is a :last-line selector. Then you could text-align:justify the main text and text-align:center the last line. That would do what you want.

Sadly, :last-line isn't a valid selector (:first-line is, but not :last-line), so that's the end of that idea.

A slightly more hopeful thought is text-align-last, which does exist as a feature. This could do exactly what you want:

text-align:justify;
text-align-last:center;

Perfect.

Except that it's non-standard and has very limited browser support.

You can read about here on MDN.

I guess as a last resort it might be an option for you, if you can live with only partial browser support. It would at least get what you want for some of your users. But that's not really a sensible way to go.

My gut feeling though is that this as as close as you're going to get. Tantalisingly close to what you want, but just not quite there. I hope I'm proved wrong, but I'll be surprised. Too bad though, because I it would seem like a perfectly logical thing to want to do.

Spudley
  • 166,037
  • 39
  • 233
  • 307
  • Nice write-up, and great link. This is a really great and far-reaching technique! – ralph.m Jun 06 '13 at 14:35
  • @ralph.m - yes, it's a neat idea. I'm just sorry I didn't think of it myself ;-) – Spudley Jun 06 '13 at 14:45
  • Well, that works and is resizable. But justify kills space near margins: |..| Is it possible to do something like: |......| So elems will be 'centered' and evenly spaced? – CoR Jun 06 '13 at 14:58
  • @CoR - add equal `padding-left` and `padding-right` to your container element. http://jsfiddle.net/ULQwf/297/ – Spudley Jun 06 '13 at 15:00
  • @Spudley: It's not wirking if user resize container div to 130px. I was looking/hoping for something auto. If it's not possible, I'll go with justify. – CoR Jun 06 '13 at 15:07
  • @CoR - I've adjusted the fiddle again with more dynamic widths: http://jsfiddle.net/ULQwf/298/ -- alter the width of the box to see the elements re-position themselves. (I've added more elements as well so it demonstrates it better) – Spudley Jun 06 '13 at 15:11
  • This is a very useful technique, however adding an extra element will add an unwanted extra line, thus causing the whole container to expand downwards. Do you have an idea how to trim the extra line? – Dean Oct 25 '14 at 11:55
  • Quick comment: you need space between the inside element to be words. Otherwise Firefox won't align it. – FlogFR Aug 28 '18 at 12:31
  • Maybe use the nth-child css selector and get the last child some how? Not sure.. not real familiar with it... – Shmack Feb 09 '20 at 20:41
3

I worked on your example, you have to make a combination of block / inline style since the justify alone just work for inline (text).

div{
    width:530px; /* I changed the div size, because you a have fixed width otherwise you should use scrolling */
    border:1px red solid;
    text-align:justify;    /* You will justify to 100$ of containing div, if you want to "center" just add another div with % size and centered */

}
div span{ /* I worked with your example you may use a class */
    width:60px;
    border:1px yellow solid;
    display: inline-block; /* Inline-block */ 
    position: relative; /* relative to container div*/
}

div:before{
    content: ''; /* position for block element*/
    display: block; /* the block part for the last item*/
    width: 100%;
}

div:after {
    content: '';
    display: inline-block; /* inline-block for the first (and middle elements) */
    width: 100%;
}
Ezequiel Gorbatik
  • 2,475
  • 1
  • 16
  • 19
-1

If tried a different approach, in the fiddle looks pretty similiar to the picture but the space is fixed in both lines but the elements are intercalated.

div{
    width:250px; /* I changed the div size, because you a have fixed width otherwise you should use scrolling */
    border:1px red solid;
    text-align:center;    /* You will justify to 100$ of containing div, if you want to "center" just add another div with % size and centered */
}
div span{ /* I worked with your example you may use a class */
    width:60px;
    float:justify;
    border:1px yellow solid;
    display: inline-block; /* Inline-block */ 
      margin-left:2%;
    margin-right:2%;

}
Ezequiel Gorbatik
  • 2,475
  • 1
  • 16
  • 19