Two-End Alignment Layout for Lists with display:inline-block/text-align:justify

by zhangxinxu

1. What Two-End Alignment for List Elements Means

First, let’s talk about what two-end alignment is. The screenshot below is the right edge of a left-aligned English paragraph in Word:
Left-aligned text in Word, by Zhang Xinxu - Xin Space - Xin Life

As you can see, the right side is ragged. Now select the text and click the justify button at the top of Word, as shown below:
Clicking the justify button in Word, by Zhang Xinxu - Xin Space - Xin Life

The right edge of the text then looks like this:
Justified text in Word, by Zhang Xinxu - Xin Space - Xin Life

The right side is now perfectly aligned, meaning the whole block of text is displayed flush against both the left and the right edge. And here, “list elements” refers to repeated list elements with a similar structure, for example the image list on QQ Alumni:
List layout illustration, by Zhang Xinxu - Xin Space - Xin Life

Two-end alignment for list elements means that the first element of each row lines up with the left edge of the parent container, and the last element lines up with the right edge of the parent container. For example, the hot-selling items on the Taobao homepage, or the popular shares list on Renren (screenshot below):
Two-end aligned popular shares list on Renren, by Zhang Xinxu - Xin Space - Xin Life

I think that when we build pages day to day, we often get design mockups with comfortable two-end aligned list elements too.

2. How to Achieve Two-End Alignment for Elements

In CSS2, text-align has a value called justify, which means “align to both edges”. What it achieves is making a line of text display aligned at both ends (the text content must exceed one line). If your browser’s address bar starts with http://www.zhangxinxu.com/, you’ll find that every one of my articles is displayed justified, so sometimes the text ends up looking very sparse, as shown below.

Sparse arrangement under justified text, by Zhang Xinxu - Xin Space - Xin Life

The purpose text-align was created for is controlling the alignment and display of text — you can tell that from the property name. From how it renders and parses, it is mainly used to control the alignment and display of inline-level elements or inline-block elements, such as text nested inside inline tags, images, input form controls, and so on; it has no effect on block-level elements. So, for list elements, in theory we could just make the originally block-level list elements inline or inline-block and easily achieve two-end alignment. In practice, though, making them inline is clearly impossible, because you can’t give list elements a fixed width and height or set vertical spacing — the list elements would be a puddle of mud, useless for building a house; and making them inline-block also faces obstacle after obstacle, because IE6/7 doesn’t truly support the inline-block property. So what looks simple in theory still needs careful planning in practice.

3. How Two-End Alignment for List Elements Is Done Today

There are plenty of methods. ① First, look at the example of the hot-selling items on the Taobao homepage, shown in the screenshot below:

Hot-selling items on the Taobao homepage, by Zhang Xinxu - Xin Space - Xin Life

Its list layout uses the traditional float layout, and it forces the parent container wider via the width property to produce the apparent “two-end alignment” effect.
Widening the container on the Taobao homepage to achieve two-end alignment, by Zhang Xinxu - Xin Space - Xin Life

② Next, look at how Renren’s popular shares achieve the two-end alignment effect. As I mentioned in my earlier article “List layout based on display:inline-block“, the list layout on Renren here is an inline-block layout.
Renren popular shares inline-block layout, by Zhang Xinxu - Xin Space - Xin Life

It also achieves the apparent “two-end alignment” effect by widening the parent tag, but it doesn’t widen it through the width property — it uses a negative margin (I personally recommend a negative margin over a fixed width):
Widening the parent container with a negative margin, by Zhang Xinxu - Xin Space - Xin Life

③ There is also a method using white-space: nowrap. This method has to be used on top of an inline-block layout, and is generally used to achieve the apparent “two-end alignment” effect for single-row list elements. white-space: nowrap forces list elements not to wrap, so you don’t need to set the width of the parent tag container or widen the parent container with a negative margin or the like. I won’t go into detail here; someday I’d like to properly discuss white-space: nowrap, a very useful CSS declaration. Those are the common methods today for achieving the apparent “two-end alignment” effect for list elements. So, isn’t each one of them a hassle — first, arranging the list elements is already troublesome in itself (fixed width, computing spacing), then you have to artificially widen the parent container, and on top of that the ancestor elements need overflow hidden (overflow:hidden), oh, my lady gaga. I think that’s why there are ranting front-end engineers on the web roaring about overtime (about that picture, you can click
here
to view it). In fact, all this work can be done while drinking coffee and browsing Weibo — the key is to use text-align:justify to do the two-end alignment layout.

4. The Benefits of text-align:justify for Two-End Alignment

The benefit is that it’s simple and convenient. With just one simple text-align:justify declaration, the elements inside automatically lay out evenly spaced and aligned at both ends! There’s no need to calculate the margin spacing between each list element, let alone modify the parent container’s width.

5. About display:inline-block List Layout

The content of this article is based on display:inline-block list layout, so if you only know float layout I suggest you carefully read my earlier article “Goodbye, float layout – display:inline-block based list layout“. That article explains in great detail the past and present of display:inline-block list layout, and I believe you’ll get a lot out of it. You may have noticed that at the end of that article I already briefly mentioned two-end alignment under text-align:justify. However, there I only showed a simple example; I did not elaborate on some display issues (such as the tragic last row), nor on the caveats for implementing it in IE6/7 and IE8. This article is here to solve those problems.

6. Two-End Alignment Layout for Lists with display:inline-block/text-align:justify

For the sake of clear logic, let’s set IE6 and IE7 aside for now and look at how IE8+ and modern browsers achieve two-end alignment of list elements with display:inline-block + text-align:justify. It’s actually very simple. Let’s take the most common list tags — ul and li — as an example. To achieve two-end alignment of the li list, this little bit of CSS is all you need:

ul{text-align:justify;}
li{display:inline-block;}

So simple it makes you spit three pints of blood on the spot. The only thing to watch out for is that the list elements must have whitespace (or a line break) at the start and end tags, as shown below:
Line break around the start and end tags, by Zhang Xinxu - Xin Space - Xin Life

Whitespace around the start and end tags, by Zhang Xinxu - Xin Space - Xin Life
The closing tag of one tag group must not be joined directly to the opening tag of the next tag group, as shown below:

Tags must not be joined together, by Zhang Xinxu - Xin Space - Xin Life

What’s more, in IE8 the list elements must not sit in a font-size:0 environment — at least font-size:1px, because IE8 wipes out the newline whitespace or ordinary whitespace when font-size:0, making two-end alignment impossible. OK, now for the main event: the tangled IE6/IE7 browsers. Clearly the ul, li style combination above doesn’t work in IE6/7 — even if you use a hack to give the li tag inline-block-like behavior in IE6/7, it still won’t help. So how can list elements in IE6/7 also support the text-align:justify property? After repeated testing and debugging, I summarized two points: inline tag-ification and consecutive closing tags. 1. Inline tag-ification By “inline tag-ification” I mean the list elements need to use inline-level tags, such as span, a, strong, em, and so on; tags like li and div won’t do. 2. Consecutive closing tags By “consecutive closing tags” I mean the closing tags of the list elements and their inner tags need to be joined together. For example, the following won’t work:

<span>
    <a href="#">
        <img src="test.jpg" />
    </a>
    <span>描述</span>
</span>

It should look like this instead:

<span>
    <a href="#">
        <img src="test.jpg" />
    </a>
    <span>描述</span></span>

We’re used to structured indentation, so writing consecutive closing tags like that looks unnatural and a bit awkward. But there’s no way around it if you want the effect. Note: if the list tags are nested multiple levels deep, the closing tags at every level must be consecutive. Once IE6/IE7 satisfies both inline tag-ification and consecutive closing tags above, plus the whitespace around start and end tags required by modern browsers, IE6/IE7 can also achieve two-end alignment for list elements! To make it easier to see at a glance what to watch out for in each browser, I’ve made the following table:

Caveats for implementing two-end alignment layout under text-align:justify in each browser

Browser

Caveats

IE6

inline-level list tags, consecutive list closing tags, line break or whitespace between list elements

IE7

inline-level list tags, consecutive list closing tags, line break or whitespace between list elements

IE8

line break or whitespace between list elements, the font size of the list elements’ environment must not be 0

Modern browsers

line break or whitespace between list elements

However, there’s still one tragic problem unsolved: the tragedy of when the last row of list elements can’t be aligned at both ends. As shown below:
The tragic last row under text-justify, by Zhang Xinxu - Xin Space - Xin Life
Actually this problem is very easy to solve. How to turn tragedy into comedy? For a list (or text) to be justified, the content must exceed one line. So to solve the problem of the last row not being aligned at both ends, all you need is to create a transparent inline-block tag layer at height 0 and width 100% at the end of the list (or text block), for example:

.justify_fix{display:inline-block; width:100%; height:0; overflow:hidden;}

With HTML like:

For example, take the earlier demo with the tragic last row: now add the span element with the class name justify_fix above to the end of that demo’s list, and the last row becomes justified, as the change shows below:
The last row elements are justified too, by Zhang Xinxu - Xin Space - Xin Life

No matter what version of browser you have, you can click right here:

Demo of a beauty list with the last row justified too
Change the browser width and you can see the two-end alignment effect more directly. Addition on 2011-03-16: Often we want the last row of the list to be left-aligned rather than justified — what do we do then? The principle is the same as the two-end alignment above. Just copy a few of the outer tags of the list elements, same width but height 0, with an &nbsp; inside (indispensable). The number of copies is generally the number of list elements per row, which guarantees the last row of elements will be left-aligned! HTML code as below:

<div class="box">
    <span class="list"><img src="http://image.zhangxinxu.com/image/study/s/s128/mm9.jpg" />
哇哦,美女,口水,鼻血~~~</span>
    <span class="list"><img src="http://image.zhangxinxu.com/image/study/s/s128/mm9.jpg" />
哇哦,美女,口水,鼻血,不行了,我的小兔乱撞~~</span>
    .
    .
    .
    <span class="list left_fix">&nbsp;</span>
    <span class="list left_fix">&nbsp;</span>
    <span class="list left_fix">&nbsp;</span>
    <span class="list left_fix">&nbsp;</span>
    <span class="list left_fix">&nbsp;</span>
</div>

The left_fix style in the HTML above is as follows:

.left_fix{height:0; padding:0; overflow:hidden;}

The result is that the last three images, previously aligned with equal width, are now vertically aligned with the elements above and left-aligned! (The screenshot below is from IE7.)
Achieving left-aligned elements in the last row, by Zhang Xinxu - Xin Space - Xin Life

You can click right here:
Demo of last-row elements arranged left-aligned

So, combining everything discussed above, we can achieve a relatively perfect two-end alignment effect for list elements under text-align:justify.

7. A Working Example of Two-End Alignment under text-align:justify

Let’s take the inline-block list layout from Renren’s popular shares above as an example. You can click right here:

Demo of two-end alignment under text-justify for Renren’s popular shares list

The effect is shown below (screenshot from IE7):

Two-end alignment under justify for Renren's popular list, by Zhang Xinxu - Xin Space - Xin Life

The CSS code is as follows:

.video-list{width:540px; margin-left:auto; margin-right:auto; text-align:justify;} /*list parent container*/
.text-justify-list{display:inline-block; width:97px; margin-bottom:15px; text-align:left; vertical-align:top;}/*list element*/

.
. /\* full Renren CSS code*/
.

.justify_fix{display:inline-block; width:100%; height:0; overflow:hidden;}/*last-row tragedy becomes comedy*/

As you can see, the list elements have no vertical margin or padding set at all — just a width — yet the list elements are indeed aligned at both ends with even spacing. No calculations, no deliberately widening the parent container; it’s implemented super simply. Comparing with the caveats mentioned above, let’s see how the HTML code in this example puts them into practice:
① inline-level tags As shown in the screenshot:
Screenshot of inline tags in use, by Zhang Xinxu - Xin Space - Xin Life

② consecutive list closing tags As shown below:
Consecutive closing tags, by Zhang Xinxu - Xin Space - Xin Life

③ line break or whitespace between list tags As shown in the screenshot:
Screenshot of list tags with line breaks that are not joined, by Zhang Xinxu - Xin Space - Xin Life
That way, you too can easily achieve two-end alignment layout for list elements, without worrying about compatibility issues!! GO! Go ahead and use it!

8. A Few Closing Words

First, about why IE6/IE7 list elements need inline-level tags and why the closing tags need to be consecutive — I don’t know the reason either. I didn’t develop the browsers; if you want to ask, go ask Mr. Gates. Second, the semantic issue. To accommodate IE6/IE7, list tags like ul and li become unusable, so the HTML semantics may drop in quality. The trade-off is in your hands. Finally, these are all things I found through my own testing. Maybe you have a better method, or can explain some of the weird behavior in IE6/IE7 — feel free to discuss in the comments. My experience is limited, so there are bound to be inaccurate statements in this article; corrections are welcome. Original article — please indicate the source when reprinting: Zhang Xinxu - Xin Space - Xin Life[http://www.zhangxinxu.com]