CSS魔法堂:"那不是bug,是你不懂我!" by inline-block
前言
每当来个需要既要水平排版又要设置固定高宽时,我就会想起display:inline-block
,还有为了支持IE5.5/6/7的hack*display:inline;*zoom:1;
。然后发现盒子间无端端多了个不可选的空白符,于是想尽办法修复这个bug。
直到一天拜读了@一丝姐、@HAX等高人的秘笈后才顿悟,原来我错了。那不是bug,是我不懂而已。
先行者——IE5.5中的inline-block
当我们为支持IE5.5/6/7而添加这段hack时*display:inline;*zoom:1
,总以为从IE8开始才支持display:inline-block
属性值。其实从IE5.5开始已经支持了,只是IE5.5/6/7支持的是IE的自定义标准,而从IE8开始则是支持CSS2.1标准而已。
https://msdn.microsoft.com/library/ms530751%28v=vs.85%29.aspx
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.
<style type="text/css">
.bk1{
background: #06F;
}
.bk2{
background: #F60;
}
.item{
width: 100px;
height: 100px;
display:inline-block;
}
</style>
<div class="bk1 item"></div>
<div class="bk2 item"></div>
<span class="bk1 item"></span>
<span class="bk2 item"></span>
经过CSS2.1洗礼的我们对上述内容不禁会发出两个疑问:
- 为啥block-level element设置了
display:inline-block
后还是垂直方向排列呢? - 为啥inline-level element设置了
display:inline-block
后之间没有诡异的间隙呢?
还记得杨过是如何变成神雕大侠的吗?不就是被断右臂后发现左手才是真爱吗:)
好了,其实我的意思是抛弃过去对display:inline-block
的认知,重新来理解IE5.5/6/7下的它才是硬道理啦。
对于问题1,首先上面的引用很直白地告诉我们——display:inline-block
能触发hasLayout,然后就没了。所以block-level element依然是block-level element,不会一夜成了inline-level element的。结论:display:inline-block
仅会触发hasLayout,而元素本该怎么排版还是怎么排版。关于hasLayout的内容可参考《CSS魔法堂:hasLayout原来是这样!》
对于问题2,我们先看看是否真的没有间隙吧!
<style type="text/css">
.bk1{
background: #06F;
}
.bk2{
background: #F60;
}
.item{
width: 100px;
height: 100px;
display:inline-block;
}
</style>
<span class="bk1 item"></span>
<span class="bk2 item"></span>
<br/><br/>
<span class="bk1 item">bk1</span>
<span class="bk2 item"></span>
见鬼了,在前一个盒子内添加些文本就出现间隙了?其实这真的和display:inline-block
无关的,大家就放过他吧!来上呈堂证供!
<style type="text/css">
.bk1{
background: #06F;
}
.bk2{
background: #F60;
}
<span class="bk1">no line break</span>
<span class="bk2">
has line break
</span>
可以看到蓝色块k和红色块h间存在一个空格,而红色块k后也存在一个空格。可是代码中我们看到蓝红色块间有4个 
HTML实体,为啥只有一个空格呢?而红色块中仅仅换了行而已,怎么就有个空格呢?
先抛结论:上面两端代码均是white space、white space collasping再作祟。
White space不仅是空格符那么简单
初看之下以为就是空格键,其实white space是一组空白字符和换行符组成。查看unicode字符集我们会发现有一大堆空白字符(如NO-BREAK SPACE等),但HTML只把ASCII space( )
、ASCII tab( )
、ASCII form feed()
和Zero-width space()
纳入white space囊中,另外还将line break(换行符)carriage return(
)
、line feed(
)
和它俩的组合纳入white space中。
inter-word space——White space的用途之一
西文是以空格来分隔单词的,而汉字间则无需空格分隔,但为了统一西文、东亚和CJK的排版,于是抽象出一个名为inter-word space的概念用于分隔词义单元,white space则作为inter-word space的值域,而定义域就是语言信息。如西文以ASCII SPACE作为inter-word space,而泰文则以Zero-width space作为inter-word space,汉语则没有inter-word space,所以word-spacing
属性不影响汉字间的距离,本来无一物何处惹尘埃呢。字形、单词间的水平距离
White space collapsing的玩法
兼容性问题又来了,因为各浏览器的实现均不尽相同。
<style type="text/css">
span{background:#F60;}
</style>
<div><span>
before</span></div>
<div><span>
before</span></div>
<div><span>after
</span></div>
<div><span>after
</span></div>
<div><span>after
</span></div>
<div><span>one
two</span></div>
<div><span>one
two</span></div>
<div><span> 
</span></div>
** chrome43 **
- 对于起始标签与第一个non-white-space字符间的white-space字符串,以
carriage return( )
作为white-space合并单元的起始符,最后保留各合并单元的合并结果。 - 结束标签与最后一个non-white-space字符间的white-space字符串,以
carriage return( )
作为white-space合并单元的结束符,最后保留各合并单元的合并结果。 - 词义单元间的white-space字符串,以
carriage return( )
作为white-space合并单元的分界符,最后保留各合并单元的合并结果。 - 标签内仅包含white-space字符串,那么这些white-space字符串将被忽略。
** FF5.0 **
- 对于起始标签与第一个non-white-space字符间和结束标签与最后一个non-white-space字符间的white-space字符串将被忽略。
- 词义单元间的white-space字符串,以
carriage return( )
作为white-space合并单元的分界符,最后保留各合并单元的合并结果。 - 标签内仅包含white-space字符串,那么这些white-space字符串将被忽略。
** IE8+ **
- 对于起始标签与第一个non-white-space字符间和结束标签与最后一个non-white-space字符间的white-space字符串将被忽略。
- 词义单元间的white-space字符串,合并为1个(ASCII space)字符。
- 标签内仅包含white-space字符串,那么这些white-space字符串将被忽略。
** IE5.5/6/7 **
- 对于起始标签与第一个non-white-space字符间的white-space字符串将被忽略。
- 结束标签与最后一个non-white-space字符间的white-space字符串,合并为1个(ASCII space)字符。
- 词义单元间的white-space字符串,合并为1个(ASCII space)字符。
- 标签内仅包含white-space字符串,那么这些white-space字符串将被忽略。
合并单元:合并单元包含0到N个white-space字符串,最终合并为0到1个white-space字符
SGML描述B.3.1 Line breaks
specifies that a line break immediately following a start tag must be ignored, as must a line break immediately before an end tag. This applies to all HTML elements without exception.
<A>My favorite Website</A>
<A>
My favorite Website
</A>
望文生义翻译法:标签与正文间的line breaks要被忽略掉!也就是上下两种HTML格式的渲染效果应该一致。实际上除了IE5.5/6/7外其他浏览器均遵守之一规定的。也许你会说上面的实验不是已经证明chrome43不遵守这个法则吗?其实
<A>
My favorite Website
</A>
HTML格式等价于<A>#x000A;My favorite Website#x000A;</A>
而不是<A>#x000D;#x000A;My favorite Website#x000D;#x000A;</A>
。现在大家都清楚了吧:)
绕到这里我想大家都有点晕了,到底这个跟问题2有啥关系呢?先不要着急嘛,我们先记住两点:
- IE5.5/6/7中"结束标签与最后一个non-white-space字符间的white-space字符串,合并为1个(ASCII space)字符";
- IE5.5/6/7中仅字符(串)可以作为词义单元,而IE8+中inline-level element也作为词义单元。
<span class="bk1 item"></span>
<span class="bk2 item"></span>
<br/><br/>
<span class="bk1 item">bk1</span>
<span class="bk2 item"></span>
IE5.5/6/7下等价于
<span>
</span>
<br/><br/>
<span>bk1
</span>
对比一下上面的规则,空隙自然就有了。
IE8+下等价于
<span>
</span>
<br/><br/>
<span>
</span>
inline-level element整体作为词义单元,从外部看根本不用管里面具体字符串是什么。
后来者居上——CSS2.1描述中的inline-block
相对IE自定义的inline-block,CSS2.1引入的inline-block就好理解多了,它做了两件事:
- 将元素变性为inline-level element;
- 让元素产生新的BFC。
消灭尾行者
现在我们终于明白通过display:inline-block
进行元素的水平排版时,为啥会有个讨人厌的跟屁虫了,那剩下的工作当然是去而快之啦。首先这个跟屁虫实质上就是white-space字符串,而我们一般会输入的就是ASCII space( )
、ASCII tab( )
和让HTML Markup更可读的line breakscarriage return(
)
、line feed(
)
。
那么消灭尾行者的方式就只有两个方向:1. 从根本上消除white-space字符串;2. 视觉效果上消除white-space字符串的影响。
牺牲HTML Markup可读性
牺牲前
<span>one</span>
<span>two</span>
<span>three</span>
牺牲后1:一行搞定(一大坨代码,会斗鸡眼的。。。)
<span>one</span><span>two</span><span>three</span>
牺牲后2:注释衔接(通过JS获取子元素数会有问题)
<span>one</span><!--
--><span>two</span><!--
--><span>three</span>
牺牲后3
<span>one</span
><span>two</span
><span>three</span>
然后@一丝姐说为展现效果牺牲结构是耍流氓,@HAX说这是"削足适履"。虽说这方法从根本上清除了white-space字符串,但那种丑不是一般人能接受的。
font-size:0
大法
这种方式存在兼容性的问题,而且子元素需要重新设置font-size
以保证后续采用em设置属性值正确有效这个就是一个巨蛋疼的事了。
负margin-right法
原理是通过负margin-right将white-space字符收入盒子后方,而margin-right的属性值需要根据font-size来决定,必须恰恰等于字形宽度的负数,否则会出现元素重叠的问题。(IE5.5/6/7不兼容这玩法)
引入HTML预编译
引入如Jade等HTML模板引擎,开发和维护时采用可读性可维护性更高的语言,而浏览器运行时则采用效率更佳但可读性差甚至非人类友好的编码,然后通过如sourcemap来做映射。
但若仅仅为解决本文的问题而引入HTML模板引擎,是不是小题大造了呢?
用float啦!
既然上述方式皆不爽,而你又熟知float的使用和注意事项,那直接换成float就好了。float的内容可参考《CSS魔法堂:说说Float那个被埋没的志向》
总结
原来display:inline-block
受委屈的这么多年,现在总算沉冤得雪了!都怪CSS2没有专门的布局模块,逼得我们东拼西凑地拼页面。所幸的是CSS3专设了Flexbox/Grid/Multi-columns Layout Modules,我们可以寄望更美好的将来了!
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/5396037.html_肥仔John
感谢
inline-block 前世今生
inline-block 未来
应不应该使用inline-block代替float
inline-block元素间间隙产生及去除详解
有哪些好方法能处理 display: inline-block 元素之间出现的空格?
Fighting the Space Between Inline Block Elements
拜拜了,浮动布局-基于display:inline-block的列表布局
9.1 White space
9.3.2 Controlling line breaks
CSS魔法堂:"那不是bug,是你不懂我!" by inline-block的更多相关文章
- CSS魔法堂:hasLayout原来是这样!
前言 过去一直听说旧版本IE下很多诡异bug均由一个神秘角色引起的,那就是hasLayout.趁着最近突然发神经打算好好学习CSS,顺便解答多年来的疑惑. hasLayout到底是何方神圣? hasL ...
- CSS魔法堂:Box-Shadow没那么简单啦:)
前言 说起box-shadow那第一个想法当然就是用来实现阴影,其实它还能用于实现其他好玩的效果的,本篇就打算说说box-shadow的那些事. 二话不说看效果 3D小球 <style typ ...
- CSS魔法堂:重拾Border之——更广阔的遐想
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
- CSS魔法堂:重拾Border之——不仅仅是圆角
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
- CSS魔法堂:重拾Border之——图片作边框
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
- CSS魔法堂:重拾Border之——解构Border
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
- CSS魔法堂:小结一下Box Model与Positioning Scheme
前言 对于Box Model和Positioning Scheme中3种定位模式的细节,已经通过以下几篇文章记录了我对其的理解和思考. <CSS魔法堂:重新认识Box Model.IFC.B ...
- CSS魔法堂:说说Float那个被埋没的志向
前言 定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了:2. 它跟Normal flow靠得太近了.本文尝试理清Fl ...
- CSS魔法堂:你一定误解过的Normal flow
前言 刚接触CSS时经常听到看到一个词"文档流",那到底什么是"文档流"呢?然后会看到"绝对定位和浮动定位能脱离文档流",从这句可以看到文 ...
随机推荐
- composer安装
1.首先到php.net下载对应版本的php,zip版本即可,注意windows需要vc11运行库支持 2.配置path路径添加对php解压目录的引用 3.将php.ini-development ...
- aspnet_isapi.dll设置图文介绍.net的程序实现伪静态
用URLRewriter控件 ①:首先要有这个文件URLRewriter.dll,如果没有,赶快到网上下载一个,并将其放到下面的bin目录里面,并且将其引用添加到下面里面; ②:下面就是Web.Con ...
- 表格搞定 Asp.net Web 状态管理
最近在网上搜罗了 ASP.NET WEB 状态管理方面的一些内容,终于把这些内容整合总结了一下. 1. 希望自己通过整理,能够掌握一些,为自己投资. 2. 以便自己忘记,又要浪费时间搜罗. 3. 希望 ...
- [备忘]没有为扩展名“.cshtml”注册的生成提供程序
webconfig中配置 <compilation debug="true" targetFramework="4.5.1"> < ...
- TODO:小程序手机预览调试
TODO:小程序手机预览调试 1. 小程序注册,目前还未开通个人注册,主体类型为企业.政府.媒体.其他组织 2. 登录小程序,绑定开发者,获取AppID 3. 下载微信小程序示例-新片预告 https ...
- Ucos系统任务间的通信详解
物联网开发中,ucos系统任务间的通信是指,两个任务之间有数据的交互,具体的一起来看看吧. 1)消息邮箱 我们还是提供两个任务Task1和Task2,假设我们还是解决刚刚的问题,Task1进行按键扫描 ...
- 【.NET深呼吸】线程信号量(Semaphore)
Semaphore类可以控制某个资源允许访问的线程数,Semaphore有命名式的,也有不命名的:如果不考虑跨进程工作,一般在代码中使用不命名方式即可. 信号量有点类似于等待句柄,某个线程如果调用了W ...
- 【转】C# 的Brush 及相关颜色的操作
// (实心刷) Rectangle rect1 = , , , ); SolidBrush sbrush1 = new SolidBrush(Color.DarkOrchid); SolidBrus ...
- SQL 里解析 XML 格式 字段 信息
DECLARE @ItemMessage XML ),zje ),yfje ),bcje ),URL ),Remark )) SET @ItemMessage=N'<List> <i ...
- 前端学PHP之面向对象系列第三篇——三大特性
× 目录 [1]封装 [2]继承[3]多态 前面的话 php面向对象编程的三大特性是封装性.继承性和多态性.本文将介绍php的这三大特性 封装 封装就是把对象中的成员属性和成员方法加上访问修饰符( p ...