为了让任意个数的列表最后一行也是对齐排列,在列表最后会辅助列表等宽的空标签元素来占位,类似下面红色高亮HTML代码:
.justify-fix { display: inline-block; width: 128px; }
<div style="text-align: justify;">
<img src="img/mm1.jpg" width="128">
<img src="img/mm1.jpg" width="128">
<img src="img/mm1.jpg" width="128">
<img src="img/mm1.jpg" width="128">
<i class="justify-fix">i>
<i class="justify-fix">i>
<i class="justify-fix">i>
div>
图示意:
同样的,在白色背景下,似乎看上去效果还不赖,但是,如果给div容器加个背景色~~
会惊讶的发现,下面多了很大一块间隙.
为了便于大家看其究竟,我把占位i元素outline高亮下,于是,效果如下:
结果会发现,上面巨大的空隙是由占位i元素上面和下面的间隙共同组成的。
下面问题来了:上面的间隙是如何产生的?下面的间隙是如何产生的?如果去除这些间隙呢?
很多时候,复杂问题是由简单问题组合而成的,实际上,这里的间隙现象的始作俑者和上面的简单现象一样,都是vertical-align和line-height搞基带来的不好的影响。
按照之前问题解决方法,我们可以直接来个line-height:0解决垂直间隙问题:
div { line-height: 0; }
结果图片和图片之间的间隙是没有了,但是,图片和最后的占位元素之间依然有个几像素的间距,,啊啊啊啊,这究竟是什么鬼?
简单现象的背后往往有大的学问,接下来是本文的高潮了,究其原因,要说到inline-block元素和基线baseline之间的一些纠缠的关系。
⑤ inline-block和baseline
CSS2的可视化格式模型文档中有一么一段话:
The baseline of an ‘inline-block’ is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its ‘overflow’ property has a computed value other than ‘visible’, in which case the baseline is the bottom margin edge.
直译一下:
‘inline-block’的基线是正常流中最后一个line box的基线, 除非,这个line box里面既没有line boxes或者本身’overflow’属性的计算值而不是’visible’, 这种情况下基线是margin底边缘。
这段文档中出现了很多专有名词line box, line boxes等,这些是内联盒子模型中的概念,是CSS进阶必备知识。
如果大家没有足够精力去学习之,可以先看下面这张图:
上图引用张大神的
由于上面的译文是直译的,理解起来还是有些拗口,我使用通俗的话描述就是:一个inline-block元素,如果里面没有inline内联元素,或者overflow不是visible,则该元素的基线就是其margin底边缘,否则,其基线就是元素里面最后一行内联元素的基线。
纳尼,还是没反应过来?
那我们看下面这个例子,应该就知道什么意思了。
两个同尺寸的inline-block水平元素,唯一区别就是一个空的,一个里面有字符,代码如下:
.dib-baseline {
display: inline-block; width: 150px; height: 150px;
border: 1px solid #cad5eb; background-color: #f0f3f9;
}
<span class="dib-baseline">span>
<span class="dib-baseline">x-baselinespan>
会发现,明明尺寸、display水平都是一样的,结果呢,两个却不在一个水平线上对齐,为什么呢?哈哈,上面的规范已经说明了一切。第一个框框里面没有内联元素,因此,基线就是容器的margin下边缘,也就是下边框下面的位置;而第二个框框里面有字符,纯正的内联元素,因此,第二个框框就是这些字符的基线,也就是字母x的下边缘了。于是,我们就看到了框框1下边缘和框框2里面字符x底边对齐的好戏。框框2有个小彩蛋,点击可以toggle其innerHTML,会发现,如果框框2里面没文字,就和框框1举案齐眉了。
下面我们要做一件很有必要的事情,用来帮助我们理解上面复杂例子在line-height值为0后的表现,什么事情呢?哈,同境界模拟,我们也设置框框2的line-height值为0,于是,就会是下面这样的表现:
知道框框2为何又下沉了一点吗?
因为字符实际占据的高度是由行高决定的,当行高变成0的时候,字符占据的高度也是0,此时,高度的起始位置就变成了字符content area的垂直中心位置,于是,文字就一半落在看看2的外面了。
由于文字字符上移了,自然基线位置(字母x的底边缘)也往上移动了,于是,两个框框的垂直落差就更大了。
OK,明白了上面的简单例子,也就能明白上面的复杂例子。紧接着,如果我们在最后一个占位的元素后面新增同样的x-baseline字符,则:
额~居然还有小伙伴皱眉头,那我再用文字解释下:
现在行高line-height是0, 则最后的x-baseline的垂直中线就和上面一列的图片对齐,而基线呢,就在中线下面差不多半个x的高度地方,而这个高度落差就是最后图片和容器的间隙高度值,因为前面的是个空元素,基线是自身的底部,哈哈,造业啊!
OK,一旦知道了现象的本质,我们就能轻松对症下药了!要么改造占位元素的基线、要么改造“幽灵空白节点”的基线位置、要么使用其他vertical-align对齐方式~
首先,来个最有意思的方法,对吧,改造占位元素的基线。这个很简单,对吧,只要在空的
元素里面随便放几个字符就可以了,例如,里面有个x:
(这之前忘记加div的line-height:0;导致图片下方有空隙。)
改造“幽灵空白节点”的基线位置,哈哈,使用font-size,字体足够小时,基线和中线会重合在一起,什么时候字体足够小呢,就是0. 于是,CSS代码(line-height如果是相对值,line-height:0也可以省掉):
div { font-size: 0; }
使用其他vertical-align对齐方式,就是让两端对齐的列表元素vertical-align:top/bottom/…之类。
div { line-height: 0; }
.justify-fix { display: inline-block; width: 128px; vertical-align: top; }
恩恩,各种方法都完美解决了垂直间隙的问题,
至此,vertical-align和line-height的断背基友关系算是彻底暴露了,而且,从行为表现上来看,line-height是攻,vertical-align是个受。而很多内联元素的行为表现,就是这对基友搞七搞八一起搞出来的。
以前,关系处于地下的时候,我们可能不会明白,为何男厕所的卷纸用得比女厕所还快;但是,现在关系暴露了,很多以前我们想不明白的事情一下子就豁然开朗了。
因此,我们要以正确地心态去看待这对好基友,毕竟,他们可以CSS届非常重要的两个主力大将。
本文牵扯的知识点甚多,建议大家如果想在重构领域有所造诣,很多基本的却很深入的东西是很有必要弄透的。篇幅有限,有不少知识点都是一笔带过的,大家若有疑问,可以自己去检索与研究,例如,vertical-align各个值的规范解释,内联盒子模型,等等。也欢迎各种方式交流。
本文为原创文章,包含脚本行为和样式控制,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=4925