display:inline-block/text-align:justify下列表的两端对齐布局

这篇文章发布于 2011年03月13日,星期日,23:30,归类于 CSS相关。 阅读 294010 次, 今日 58 次 76 条评论

 

一、何为列表元素的两端对齐布局

首先说说何为两端对齐。下面这个截图是word中一段英文左对齐的右边缘截图:
word中文字左对齐截图 张鑫旭-鑫空间-鑫生活

可以看到右侧是参差不起的,现在,选中文字,点击word上方的两端对齐按钮,如下图:
点击word中两端对齐按钮 张鑫旭-鑫空间-鑫生活

结果文字的右边缘就成了这样:
word中两端对齐效果截图 张鑫旭-鑫空间-鑫生活

右侧完全对齐了,也就是整篇文字全部沿着左边缘和右边缘对齐显示了。

然后这里的“列表元素”指的是具有类似结构的重复列表元素,例如QQ校友中的图片列表:
列表布局示意  张鑫旭-鑫空间-鑫生活

所谓列表元素的两端对齐就是每行列表元素的第一个元素与父容器的左边缘重合,最后一个元素与父容器的右边缘重合。例如淘宝首页的热卖单品,或是人人网的热门分享列表(如下截图):
人人网热门分享列表两端对齐 张鑫旭-鑫空间-鑫生活

我想我们平时写页面的时候也经常会拿到的列表元素两端对齐的体验舒服的设计图吧。

二、如何实现元素的两端对齐

CSS2中text-align有一个属性值为justify,为对齐之意。其实现的效果就是可以让一行文字两端对齐显示(文字内容要超过一行)。如果您现在浏览器的地址是以http://www.zhangxinxu.com/打头的话,就可以发现我的每篇文章都是以两端对齐的方式显示的,所以,有时候就会出现文字非常稀松的情况,如下图所示。
文字两端对齐下稀疏的排列 张鑫旭-鑫空间-鑫生活

text-align其诞生的意义是控制文字的对齐与显示的,从其属性名上就可以看出来。从其渲染与解析上来看,其主要是用来控制inline水平元素或inline-block元素的对齐与显示的,例如嵌套行内标签的文字、图片、input表单控件等;而对block水平的元素是没有作用的。

所以,对于列表元素,理论上,我们只要将原本block水平的列表元素inline化或是inline-block化就可以轻松实现其两端对齐了。然而考虑到实际情况,inline水平化显然是不可能的,因为不能给列表元素定宽定高,设置垂直方向上的间距等,列表元素就像是一摊烂泥,根本没法用来砌房子;而inline-block化也是有重重阻碍的,因为IE6/7并不真正意义上的支持inline-block属性。

可见,理论上虽简单,实际上还得从长计议。

三、目前列表元素如何实现两端对齐的

方法多多。

① 首先看淘宝网首页热卖单品的例子,如下截图:
淘宝网首页热卖单品截图 张鑫旭-鑫空间-鑫生活

其列表布局使用的是传统的浮动(float)布局,通过width属性强行增大父容器的宽度来实现看上去的“两端对齐”效果的。
淘宝网首页增加容器宽度实现两端对齐 张鑫旭-鑫空间-鑫生活

② 再看人人网热门分享的两端对齐效果的实现方法,我在之前“基于display:inline-block的列表布局”一文中已经提过,人人网这里的列表布局为inline-block布局。
人人网热门分享inline-block布局 张鑫旭-鑫空间-鑫生活

其通过也是通过增大父标签的宽度来实现看上去的“两端对齐”效果的,不过其不是通过width属性来增加父标签的宽度的,而是使用的margin负值(我个人推荐使用margin负值而不是定宽):
margin负值增加父容器的宽度 张鑫旭-鑫空间-鑫生活

③ 还有一种方法就是利用white-space: nowrap,此方法需在inline-block布局基础上使用,一般用在实现单行列表元素看上去的“两端对齐”效果上。white-space: nowrap会强制列表元素不换行,于是你无需设定父标签容器的宽度或是通过margin负值等手段增加父容器的宽度等。这里不展开,以后有机会要好好说一说white-space: nowrap这个很有用的CSS声明的。

以上就是目前几种常见的实现列表元素看上去的“两端对齐”效果方法。怎么样,是不是每个都很折腾——首先列表元素排列就已经很折腾人的了(定宽,计算间距),然后还有人为增加父容器的宽度,同时祖辈元素还要溢出隐藏(overflow:hidden),oh,my lady嘎嘎。我想这就是为什么网上会有前端工程师咆哮体咆哮加班的原因了(关于此图,您可以点击这里查看)。

其实,这些活儿都是边喝咖啡,边看微博就可以完成的,关键使用text-align:justify来做两端对齐的布局。

四、text-align:justify实现两端对齐的好处

好处就是简单方便。只要一个简单的text-align:justify声明,里面的元素就自动等间距两端对齐布局啦!根本无需计算每个列表元素间的margin间距,更不用去修改父容器的宽度。

五、关于display:inline-block列表布局

本文的内容是基于display:inline-block列表布局的,所以如果您只知道浮动布局建议您认真看下我之前“拜拜了,浮动布局 – 基于display:inline-block的列表布局”一文,这篇文章非常详细的讲解了display:inline-block列表布局的前世今生,相信会有不少收获。您可能注意到了,在这篇文章的最后其实已经简单提到text-align:justify下的两端对齐布局,然而,那里只是简单展示了个例子,对于一些显示上的问题(例如悲剧的最后一行),以及IE6/7浏览器以及IE8浏览器下实现的注意事项并没有详细阐述,而本文就是来解决这些问题的。

六、两端对齐布局实践

为了表述上逻辑清晰。我们先把IE6和IE7浏览器晾在一边,看看IE8+浏览器以及现代浏览器下如何display:inline-block+text-align:justify实现列表元素的两端对齐。

说穿了其实很简单,我们不妨以最常见的列表标签-ul, li标签举例,要实现li列表的两端对齐,直接下面这点CSS代码就OK了:

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

简单得让人当场吐血三升。

唯一需要注意的就是列表元素首尾标签留空(或换行),如下图所示:
标签首尾换行 张鑫旭-鑫空间-鑫生活首尾标签留空 张鑫旭-鑫空间-鑫生活

不能够上一个标签组的结束标签与下一个标签组的其实标签连在一起,如下图所示:
标签不能连在一起 张鑫旭-鑫空间-鑫生活

不仅如此,对于IE8浏览器,列表元素不能处在font-size:0的环境下,至少code>font-size:1px,因为IE8浏览器font-size:0或直接把换行空格或普通空格抹掉而无法实现两端对齐效果。

ok,下面是重头戏了,纠缠不清的IE6/IE7浏览器。显然上面的ul, li样式组合在IE6/7浏览器下是行不通的,即使你使用hack让IE6/7下的li标签有类似于display:inline-block的特性也是没有作用的。那么如何才能让IE6/7浏览器也有列表元素支持text-align:justify属性呢?经过我反复试验与调试,总结了两点:inline标签化以及结束标签连续化

1. inline标签化
所谓“inline标签化”就是列表元素需要使用inline水平的标签,例如span, a, strong, em等,像li, div这些标签就不可以。

2. 结束标签连续化
所谓“结束标签连续化”是指列表元素及其内部标签的结束标签需要连在一起。例如下面这个就是不行的:

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

而应该是这个样子滴:

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

我们已经习惯了结构化的缩进,所以上面结束标签连写看上去很不自然,有些别扭。但是,为了实现效果,这是没有办法的事情。注意:如果列表标签内嵌多层,则所有层级的结束标签都要连续。

IE6/IE7浏览器同时满足上面的inline标签化以及结束标签连续化,再加上先前现代浏览器下的首尾标签留空,IE6/IE7浏览器也就能够实现列表元素的两端对齐啦!

为了便于更直观的知道各个浏览器下实现两端对齐效果需要注意的事项,我特地制作了下表:

各个浏览器实现text-align:justify下的两端对齐布局注意事项表
浏览器 注意事项
IE6 inline水平列表标签、列表结束标签连续、列表元素间换行或留空
IE7 inline水平列表标签、列表结束标签连续、列表元素间换行或留空
IE8 列表元素间换行或留空、列表元素的环境字体大小不能为0
现代浏览器 列表元素间换行或留空

 

然而,现在还有一个很悲剧的问题没有解决,就是当列表元素最后一行无法两端对齐的悲剧。如下图所示:

text-justify下悲剧的最后一行

其实这个问题很好解决的。

如何悲剧变喜剧?
列表(或文字)要两端对齐的前提就是内容必须超过一行,所以,要解决最后一行元素无法两端对齐的文字其实很简单,就是在列表(或文字段)的最后创建一个高度为0的宽度100%的透明的inline-block的标签层就可以了,例如:

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

如下HTML:

<span class="justify_fix"></span>

例如拿先前最后一行列表悲剧的demo举例,现在在该demo列表最后添加上面类名为justify_fixspan元素,结果最后一行两端对齐排列了,如下图变化:

末行元素也两端对齐了

无论您手上的是什么版本的浏览器,您可以狠狠地点击这里:末行也两端对齐的美女列表demo

改变浏览器的宽度,您可以更直观地看出两端对齐的效果。

补充 on 2011-03-16:
很多时候,我们希望列表的最后一行是左对齐排列的,而不是两端对齐,这时候怎么办呢?原理与上面的两端对齐一致。就是复制几个列表元素的外层标签,等宽,但高度为0,里面就是个&nbsp;(不可缺),复制的个数一般就是每行元素的列表个数啦,这样肯定可以保证最后一行元素一定是左对齐排列的啦!

如下HTML代码:

<div class="box">
    <span class="list"><img src="mm9.jpg" />
哇哦,美女,口水,鼻血~~~</span> <span class="list"><img src="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>

上面HTML中的left_fix样式如下:

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

结果先前等宽对齐的最后三个图片就与上面元素垂直对齐且左对齐啦!

最后一行元素左对齐实现

您可以狠狠地点击这里:最后一行元素左对齐排列demo

于是,综合上面所有讨论,我们就可以相对比较完美地实现列表元素在text-align:justify的两端对齐效果了。

补充于 2015-12-24
今天查看评论,发现好多小伙伴提到占位的元素会导致莫名的空白高度。关于这个问题,可参考“CSS深入理解vertical-align和line-height的基友关系”的“④ 复杂现象”部分。有分析原因以及提供解决方案。

七、text-align:justify下两端对齐效果实例

我们拿上面人人网热门分享处的inline-block列表布局举例。

您可以狠狠地点击这里:人人网热门分享列表text-justify下两端对齐demo

效果如下图(截自IE7浏览器):
人人网热门列表justify下两端对齐效果截图 张鑫旭-鑫空间-鑫生活

CSS代码如下:

.video-list{width:540px; margin-left:auto; margin-right:auto; text-align:justify;} /*列表父容器*/
.text-justify-list{display:inline-block; width:97px; margin-bottom:15px; text-align:left; vertical-align:top;}/*列表元素*/

.
. /* 完全人人网CSS代码*/
.

.justify_fix{display:inline-block; width:100%; height:0; overflow:hidden;}/*末行悲剧变喜剧*/

可以看到列表元素压根就没有设置垂直方向上的margin或是padding值,就单单一个宽度值,但是列表元素确实两端对齐,等间距排列。没有计算,没有有意去增加父容器宽度等,超简单就实现了。

比对上面提到的些注意事项,看看这个例子中的HTML代码是如何实践上面的注意事项的:
① inline水平标签
如下截图所示:
inline标签使用截图 张鑫旭-鑫空间-鑫生活

② 列表结束标签连续
如下图所示:
结束标签连续 张鑫旭-鑫空间-鑫生活

③ 列表标签换行或留空
如下截图所示:
列表标签换行不连续截图 张鑫旭-鑫空间-鑫生活

如此,你也可以轻轻松松实现列表元素的两端对齐布局,而且不用去担心兼容性问题!!GO!大胆的去使用吧!

八、一些补充的话语

首先是关于为什么IE6/IE7浏览器列表元素需使用inline水平标签,,同时结束标签需连续,这个问题我也是不知道为什么,浏览器不是我开发的,要问得去问盖茨先生了。

其次,语义化的问题。要兼顾IE6/IE7浏览器,像列表标签ul, li等就不能使用了,所以HTML语义上可能质量要降低了,权衡在你手。

最后,都是自己试验出来的东西,可能您有更好的方法,或者可以解释IE6/IE7下一些奇怪的行为,欢迎以评论的形式进行交流。资历有限,文中难免有表述不准确的地方,欢迎指正。

最后的最后为日本罕见大地震祈福!

(本篇完)

分享到:


发表评论(目前76 条评论)

  1. 想做自己喜欢的事说道:

    不等宽的标签能实现两端对齐的功能么?

  2. shichuanzhi说道:

    我这样写的demo,不知道为啥不行。。请大家指教

    Document

    * {
    margin: 0;
    padding: 0;
    }

    li {
    list-style: none;
    }

    .box {
    width: 100%;
    text-align: justify;
    }

    .item {
    display: inline-block;
    width: 100px;
    height: 100px;
    background-color: #8a8a8a;
    }

    • grenade说道:

      如果只有一行里面的inline-block不超过父元素的宽度就不会生效,可以上
      .box::after{
      content:”;
      width:100%;
      display:inline-block;
      }

  3. 能满足齐行,但是如果用了它标点符号就会在行首说道:

    我用您说的,在中文的时候给他在字与字中间加了空格,但是就无法实现标点符号不在行首了,请问这个要怎么解