css中display:inline-block属性值的深入解析

你真的了解 inline-block 了吗?本文将带你深入剖析该属性值的前世今生,让你更好的理解和运用 inline-block。
css中display:inline-block属性值的深入解析

曾几何时,display:inline-block 已经深入「大街小巷」,随处可见 「display:inline-block; *display:inline; *zoom:1; 」这样的代码。如今现代浏览器已经全面支持这个属性值了,上面的代码只是为了兼容 IE6、7 而已。那么你真的了解 inline-block 了吗?本文将带你深入剖析该属性值的前世今生,让你更好的理解和运用 inline-block。(本文约定 display:inline-block 简写为 inline-block)

开篇我们来看几个问题:

IE6、7 真的不支持 display:inline-block 吗?
display:inline-block 后的元素为什么会产生水平空隙,这真的是 bug 吗?
如何更好的解决 display:inline-block 元素间产生的水平空隙?

一、inline-block 前世
1.认知
也许有人问你为何要写「 display:inline-block; *display:inline; *zoom:1; 」 来兼容 IE6、7 时,你会立马答道:因为 IE6、7 不支持 display:inline-block 呗!不知道何时起,惯性思维给开发者带来了这样一个可怕的概念。万物都是辩证的,当你写下这些的时候,可曾怀疑过大众观点真的可靠吗?也许你认为这些无关 紧要,实现效果就好。但是如果不能理解每个属性或属性值的根本,你将永远无法全面的了解它,人云亦云只会让你浅尝辄止,止步不前。那么这里就涉及到所谓的 「CSS 学习瓶颈」的问题了,这个问题张鑫旭《说说CSS 学习中的瓶颈》一文有详细阐述,虽然部分观点我不是很赞同,但是中心思想还是很值得思考的。文中有几个不错的问题这里也列举出来供大家观摩:

line-height:150% 和 line-height:1.5 的区别是?
float 为何会让外部容器高度塌陷?这是 bug?(我的答案在《那些年我们一起清除过的浮动》)
vertical-align 的表现为何在IE7, IE8, IE9 下表现不尽相同?其中的渲染机制是?
好了,回到 inline-block 的认知的问题,我的观点是:

IE 从 5.5 开始就已经支持 display:inline-block 了,只是支持的并不是那么完善。

在 msdn 微软开发者社区,找到了 IE 从5.5 开始支持 inline-block 的证据:

The inline-block value is supported starting with Internet Explorer 5.5. You can use this value to give an object a layout without specifying the object’s height or width.

这里明确指出:从 IE5.5 开始支持 inline-block。

链接:http://msdn.microsoft.com/zh-cn/library/ie/ms530751(v=vs.85).aspx

那么既然 IE5.5 开始就已经支持了 inline-block,为何我们还要写那么一坨 CSS 呢?同时我们知道 IE6、7 中 display:inline-block 是可以触发 hasLayout 的,触发了 hasLayout 的元素表现出来的特征就是一个独立的矩形容器,可以设置宽高而且不受外部元素的影响,类似于现代浏览器中的 Block formatting contexts (块级格式化上下文)的概念。

下面来做一个详细的测试,分别看看 IE6 中 inline 元素和 block 元素的表现:

1)inline 元素 display:inline-block

IE6 中截图如下:

\

.dib-inline, .dib-block {
width:100px;
height:30px;
line-height:30px;
text-align:center;
}
.dib-inline {
display:inline-block;
}

测试表明:IE6 中 inline 元素只要触发了 hasLayout 其表现就类似于 inline-block,这里设置 display:inline-block; 或者 zoom:1; 等其他属性值可以触发 hasLayout ,表现出来是一样的。

查看 DEMO

2)block 元素 display:inline-block

IE6 中截图如下:

\

.dib-inline, .dib-block {
width:100px;
height:30px;
line-height:30px;
text-align:center;
}
.dib-block{
display:inline-block;
}

测试表明:IE6 中 block 元素即使触发了 hasLayout 也不能具有 inline-block 元素不换行的特性。想要 block 元素支持 inline-block 元素的特性,我们可以这样做:

.dib-block {
display:inline;
zoom:1;
}

首先让 block 元素转化为 inline 元素,强制其不换行;然后通过 zoom:1 触发 hasLayout,使其可以设置宽高。修复后的 截图如下:

\

3)结合现代浏览器

综上,现代浏览器都支持 display:inline-block ,IE6、7 inline 元素也可以达到同样的效果,IE6、7 block 元素需要设置 display:inline; zoom:1; 它们结合在一起便是:

display:inline-block; /* 现代浏览器 +IE6、7 inline 元素 */
*display:inline; /* IE6、7 block 元素 */
*zoom:1;

为了不让支持 CSS2.1 inline-block 的浏览器 重置为 inline,我们针对 IE6、7 做一个 hack。由于现代浏览器也开始支持 zoom 属性,这里只是希望 IE6、7 中生效,所以还是 hack 一下比较合适。至此产生了我们熟悉的兼容各个浏览器的 inline-block 写法。

小结:IE6、7 并不是不支持 inline-block,只是 block 元素需要做一些处理来达到 inline-block 的效果。

2. 到底什么是 inline-block
说了很多,或许很多朋友还不是太明白到底什么是 inline-block?W3C 在 CSS2.1 The ‘display’ property 中描述如下:

This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.

大致意思就是:inline-block 后的元素创建了一个行级的块容器,该元素内部(内容)被格式化成一个块元素,同时元素本身则被格式化成一个行内元素。

直白一点的意思就是:inline-block 的元素既具有 block 元素可以设置宽高的特性,同时又具有 inline 元素默认不换行的特性。当然不仅仅是这些特性,比如 inline-block 元素也可以设置 vertical-align 属性。简而言之:

inline-block 后的元素就是一个格式化为行内元素的块容器( Block container )

怎么样?听起来还不错吧!

3. inline-block 缘从何起?
前面已经证明了 IE 5.5 开始就支持了 inline-block,那么 IE5.5 是什么时候发布的呢?话说当年网景与 IE 大战,IE5.5 那是何等的风骚……(好吧,此处略去十页)。从维基百科的资料来看,IE5.5 beta1 的发布时间是:1999年12月,最终版本是 2000年7月。那么 W3C 标准中是何时才出现 inline-block 这个值的呢?

在 CSS1 规范中,「display」的值仅包括: block | inline | list-item | none 。CSS2.1中才添加了 inline-block 属性值。一丝继续舔着手指,用那苦逼的英语水平终于翻到了这份草案:http://www.w3.org/TR/2002/WD-CSS21-20020802/visuren.html#display-prop, 这份草案的日期是 2002年8月2日,纳尼!!!原来我们纠结了半天的 inline-block , IE5.5 至少提前两年就提出来了啊!难道是微软给 W3C 提议后,CSS 2.1才加入的?(不过我看到 W3C 官网有一个关于是否增加 inline-block 的投票)好吧这个问题也许有一天 IE 某个开发者写《 IE回忆录》的时候我们才能了解到其中的内幕。如果找到更早关于 inline-block 的 CSS草案,也麻烦告知一丝一声。好吧,如果你还不相信,打微软官方电话问问吧 800-820-3800(不是 DHC 哦!)。

原来我们一直讨论的 inline-block 在 IE 6、7中和 CSS2.1 中的(现代浏览器所支持的) inline-block 上压根不是一个东东嘛,IE6、7 中的 inline-block 更像是 IE 的私有属性值,他们本身就不具有可比性。简单、绝对的认为 IE6、7 不支持 inline-block 好比一叶障目,看到前面,却看不到后面,太过于片面。诚然,IE6、7 的 hasLayout 给我们带来了很多麻烦,但是不得不承认微软的 IE 在网页多语言文本混排上的先进性,尤其是 CJK 文字和西文的混排,超越其他浏览器至少5年。

总结:

IE5.5 后开始支持 inline-block, 但是它所支持的 inline-block 不能等同于 CSS2.1 中的 inline-block,因为 IE5.5 比 CSS2.1 更早提出 inline-block 的概念并作为所谓的「私有属性值」使用,所以二者表现出来的效果是不完全一致。
IE 5.5、6、7 、8(Q)中 block 元素对 inline-block 支持不完整,如果要达到类似的效果,需要先设置为 display:inline,然后使用 zoom:1 等触发 hasLayout。
IE 5.5、6、7 、8(Q)中 inline 元素欲达到 inline-block 的效果只需直接设置此属性值或使用 zoom:1 等均可。
各浏览器对 display 属性的支持情况请参阅:《各浏览器对 ‘display’ 特性值的支持程度不同》

\

二、inline-block 今生
1. display:inline-block 后的元素为什么会产生水平空隙,这真的是 bug 吗?
这么一个神奇的属性,为何大家一直避而远之呢?这恐怕还得从 inline-block 元素之间产生的水平空隙(间隙)说起吧。

参照 DEMO

现代浏览器中 inline 和 block 元素 display:inline-block 后均会产生水平空隙;

\

IE6、7,IE8(Q)模拟 display:inline-block 后分两种情况:

\

IE6、7,IE8(Q)中:inline 元素会产生空隙,block 元素不会产生空隙。
看看 inline 元素默认的表现情况如何?原来默认就有空隙存在!它们是谁?是空白符(white space)!

\

W3C 9.1 White space 中规定以下元素属于空白符(white space):

ASCII 空格 ( )
ASCII 制表符 (	)
ASCII 换页符 ()
零宽度空格 (​)「这个在闭合浮动中也有运用到」
9.3.2 Controlling line breaks 中进一步阐述:

A line break is defined to be a carriage return (
), a line feed (
), or a carriage return/line feed pair. All line breaks constitute white space.

For more information about SGML’s specification of line breaks, please consult the notes on line breaks in the appendix.

折行被定义为一个回车符(
),一个换行符 line feed (
),或者一个回车、换行的组合。所有的折行构成了空白符。

有关 SGML 规范中折行的更多信息,请参阅附录中关于折行的注释。

通常情况下,对于多个连续的空白符(空格,换行符,回车符等),浏览器会将他们合并为一个空白符。CSS 中由 white-space 这个属性来控制:

white-space:normal | pre | nowrap | pre-wrap | pre-line

默认值:normal

normal:默认处理方式。
pre:用等宽字体显示预先格式化的文本,不合并文字间的空白距离,当文字超出边界时不换行。可查阅 pre 对象
nowrap:强制在同一行内显示所有文本,直到文本结束或者遭遇 br 对象。
pre-wrap:用等宽字体显示预先格式化的文本,不合并文字间的空白距离,当文字碰到边界时发生换行。
pre-line:保持文本的换行,不保留文字间的空白距离,当文字碰到边界时发生换行。

\
注:IE7及更早浏览器不支持 CSS2.1 新增的 pre-wrap | pre-line。

所以这并不是 inline-block 后产生的 bug,而是因为 inline-block 具有 inline 元素固有的特性。那么为何 IE6、7 block 元素没有产生空隙呢?其实前面也提到了 IE 的 hasLayout,具有独立性,所以产生 hasLayout 的元素之间表现出来互不影响,这也再次表明 IE6、7 中的 inline-block 不能等同于 CSS2.1 中的 inline-block。如果非要说是有 bug, IE6、7 block 元素 inline-block 后不产生空隙才是 bug。

测试表明删除换行符后,inline 元素间的空隙就「消失」了:

\

2.去掉 inline-block 产生的空隙
为了让各个浏览器表现一致,更好的还原视觉设计搞,很多时候我们需要去掉 inline-block 产生的空隙。

上一节中我们已经知道产生空隙的根本性原因是:

HTML 中的换行符、空格符、制表符等产生了空白符,而这些归根结底都是字符,那么它们的大小都是 受 font-size 来控制的,字体大小直接导致 inline 或者 inline-block 后元素之间空隙的大小,把 inline-block 元素间的空隙认为总是某个固定大小是错误的。

用 GIF 动画的形式来表明对应关系:



很清楚的看到,当 font-size:0 的时候元素间的空隙都为0了,或许到这里你会感到很欣喜了,原来掌握的根本性原因这么简单就搞定了啊!

加载中

关键字

喜欢这篇文章?马上分享它!

延伸阅读