[关闭]
@king- 2014-12-04T17:36:59.000000Z 字数 4981 阅读 993

inline-block在低版本浏览器和现代浏览器中的表现

CSS


首先从字面上我们就可以看出来inline-block是一个具有inline特性同时也具有block特性的属性值,同时他也被深入了人心,因为当我们需要一个标签有自己的宽高同时又是内链标签的时候我们就会想起他。

  1. display:inline-block;/*ie8后的现代浏览器支持*/
  2. /*下面是ie低版本浏览器兼容写法,设置标签为内链标签,并通过zoom触发ie的hasLayout特性*/
  3. *display:inline;
  4. *zoom:1;

到底什么是 inline-block

在W3C CSS2.1中的9.2.4 The 'display' property是这样定义inline-block属性值的

inline-block
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 的元素既具有 block 元素可以设置宽高的特性,同时又具有 inline 元素默认不换行的特性。当然不仅仅是这些特性,比如 inline-block 元素也可以设置 vertical-align 属性。

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

这里我们不讨论ie6-7是否支持 inline-block 属性值的问题,具体的可以查看《inline-block 前世今生》

该文中已经强调,IE从IE5.5开始就存在inline-block这个属性值了,甚至比CSS2.1中提出inline-block还早,只是两者并不是同一个inline-block

这里确实有点绕,具体的还请看博文去吧。

inline-block中出现元素尾部有水平空隙的问题

在上面我们已经提过,inline-block是一个包含有inline特性和block特性的属性值。那么单我们分解来看,我们就能清楚的知道这个水平空隙是何来的。
HTML:

  1. <div class="d1">我是一个div标签,我的display属性为block</div>
  2. <div class="d2">我也是一个div标签,我的display属性为block</div>
  3. <span class="s1">我是一个span标签,我的display属性为inline</span>
  4. <span class="s1 s2">我是另一个span标签,我的display属性也为inline</span>
  5. <span class="s1 s3">我是另一个span标签,我的display属性也为inline</span>

CSS:

  1. body,
  2. div,
  3. span {
  4. padding: 0;
  5. margin: 0;
  6. }
  7. .d1,
  8. .d2 {
  9. overflow: hidden;
  10. border: 1px solid #cba;
  11. font-size: 30px;
  12. }
  13. .s1 {
  14. background: #f29c9c;
  15. font-size: 30px;
  16. font-weight: 700;
  17. }
  18. .d1,
  19. .s2 {
  20. background: #a2a4cb;
  21. }
  22. .d2,
  23. .s3 {
  24. background: #a2cba5;
  25. }

inline属性与block属性
从图中我们可以看出,带有block的div元素是完整填充整个块的,但是带有inline的span元素则在元素尾部带有留白的空隙,同时元素的上下也带有较为明显的水平留白。那么从这里我们就可以推断出。inline-block中的尾部水平空隙是inline带来的。

问题扩展

那怎么inline中的上下水平留白在inline-block中不见了呢?

通过实验后你会发现,当你设置 inline 元素的 line-height 高度为其自身字体(内容)高度的时候,这样的上下留白问题就解决了。为什么会这样,作为菜鸟级的我分析为

inline是没有宽高的,而他的可见是又自身内容所支撑出来的,而字体在计算的时候不同的浏览器,不同的字体所计算出来的实际高度都是大于字体本身大小并在浏览器中存在计算差异,这一点可以查看《line-height和字体实际高度的计算》
而inline-block是有宽高的,他并不是又内容支撑起来的,所以在inline-block中就不存在这一的问题

如何将inline的上下水平留白去除呢
因为inline的宽高是由内容支撑的,那么我们去修改他的内容就可以了,在上面我们知道了,文字的实际高度和line-height是不统一的,那么我们只需要设置他们统一就可以解决这一的问题了;
设置font-size的大小和line-height相等

  1. font-size: 30px;
  2. /*方法一*/
  3. line-height:30px;
  4. /*方法二*/
  5. line-height:1;
  6. /*方法三*/
  7. line-height:100%;

在这里,方法一很容易理解,也就是我们经常能看到的;而其实line-height属性值除了能接受带有单位的值以外,其实还能接受百分比、直接的数值;这个在 W3C line-height中有明确说明。
方案二,方案三类似因为1=100%、1.5=150%,而且这样的方式不需要考虑font-size的具体值。

inline-block元素尾部有水平空隙的解决方法

1. display:inline-block 后的元素为什么会产生水平空隙,这真的是 bug 吗?

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.

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

有关 SGML 规范中折行的更多信息,请参阅附录中关于折行的注释。
通常情况下,对于多个连续的空白符(空格,换行符,回车符等),浏览器会将他们合并为一个空白符。CSS 中由 white-space 这个属性来控制:
white-space:normal | pre | nowrap | pre-wrap | pre-line

默认值:normal

注: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了,或许到这里你会感到很欣喜了,原来掌握的根本性原因这么简单就搞定了啊!

然,理想是丰满的,现实是骨感的。
大部分浏览器是支持 font-size:0 的。很明显,我们要和 IE 6、7 这两个妖孽进行一番战斗。

去除 inline-block 空隙终极解决方案(2012年8月17日更新)

  1. .dib-wrap {
  2. font-size:0;/* 所有浏览器 */
  3. *word-spacing:-1px;/* IE6、7 */
  4. }
  5. .dib-wrap .dib{
  6. font-size: 12px;
  7. letter-spacing: normal;
  8. word-spacing: normal;
  9. vertical-align:top;
  10. }
  11. @media screen and (-webkit-min-device-pixel-ratio:0){
  12. /* firefox 中 letter-spacing 会导致脱离普通流的元素水平位移 */
  13. .dib-wrap{
  14. letter-spacing:-5px;/* Safari 等不支持字体大小为 0 的浏览器, N 根据父级字体调节*/
  15. }
  16. }
  17. .dib {
  18. display: inline-block;
  19. *display:inline;
  20. *zoom:1;
  21. }

YUI解决方案
其实在 YUI 3 中也全面运用了 inline-block 作为基础布局,YUI 3 是这样解决的:

  1. .yui3-g {
  2. letter-spacing: -0.31em; /* webkit: collapse white-space between units */
  3. *letter-spacing: normal; /* reset IE < 8 */
  4. word-spacing: -0.43em; /* IE < 8 && gecko: collapse white-space between units */
  5. }
  6. .yui3-u {
  7. display: inline-block;
  8. zoom: 1; *display: inline; /* IE < 8: fake inline-block */
  9. letter-spacing: normal;
  10. word-spacing: normal;
  11. vertical-align: top;
  12. }

显然,这里纯粹使用了 letter-spacing 和 word-spacing 来控制元素间的空隙,局限性极大,-0.31em 和 -0.43em 只是因为 YUI 3 全局 cssfonts.css 里设置是:「body { font:13px/1.231 arial,helvetica,clean,sans-serif; }」。

当然,如果你坚持使用把 html 写在一行的方式来达到去除 inline-block 空隙的目的,我只能说:一切以牺牲结构来兼容表现的行为都是耍流氓!所以探讨此种方式去除空隙也将是无意义的,不在本文和作者考虑范围之内。

文章内容为个人整理,主要内容来自inline-block 前世今生

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注