处处留心皆学问——由“display:inline-block;”导致的间距引发的思考
文章开始之前先做个小测试,请看以下代码,选择对应的页面展示:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>测试</title> </head> <style> ul{ background: lightblue; } ul li{ display: inline-block; background: pink; padding: 0; margin: 0; } </style> <body> <div> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> </body> </html>
对应页面效果:
A:
B:
恩,如果你选择好了,可以想一下自己为什么选择这个结果。然后如果原因很清晰,恭喜你,后面的就不用看下去了 ̄□ ̄||。
如果,还有点迷惑,可以往后再走马观花下^_^。
现在,切入正题。在做一个demo时遇到了一个问题:我有五个li需要并排排列,然后自然而然的我给它们设了display:inline-block;但是,过了很久之后发现,除了我写的样式外,它默认有一个间距,我们都不喜欢不可控的事,在布局的时候亦是如此,样式中检查了查了好久margin,padding,定位等等都不是,于是就求救万能的谷歌,原来好多人都遇到过这个问题。
一、间距原因
由于换行导致的空白符导致的。空白符,white space,W3C 9.1中定义包括如下元素:ASCII 空格 ( )ASCII 制表符 (	)ASCII 换页符 ()零宽度空格 (​)。W3C 9.2中进一步进行阐述,折行也被定义为空白符,“折行被定义为一个回车符(
),一个换行符 line feed (
),或者一个回车、换行的组合。所有的折行构成了空白符”。
通常情况下,对于多个连续的空白符(空格,换行符,回车符等),浏览器会将他们合并为一个空白符。CSS 中由 white-space 这个属性来控制:
white-space:normal | pre | nowrap | pre-wrap | pre-line
默认值:normal
normal:默认处理方式。
pre:用等宽字体显示预先格式化的文本,不合并文字间的空白距离,当文字超出边界时不换行。可查阅 pre 对象
nowrap:强制在同一行内显示所有文本,直到文本结束或者遭遇 br 对象。
pre-wrap:用等宽字体显示预先格式化的文本,不合并文字间的空白距离,当文字碰到边界时发生换行。
pre-line:保持文本的换行,不保留文字间的空白距离,当文字碰到边界时发生换行。
这样,知道了是谁在捣乱就可以去 轰走它了。空白符可以删除,也就是说把所有li放在一行,显然这样不太可读和整齐;第二种方法,空白符也是一个字符,既然是字符就会受字体大小约束,它是ul的子元素,那么我们可以给父元素设置字体大小为0px,这样虽然空白符还在,但是已经显示不了了。为了不影响后面正常字体的显示记得在li内部要设置正常的大小值。知识有限先给出这两种解决方法,肯定还有很多其他更好的方法,欢迎知道的小伙伴们评论区告知。
二、延伸
在查资料的过程中,看到了一些相关的知识点,先简单记录,可能有些突兀和不连贯。后面有时间了继续补充完整。
1.hasLayout :
haslayout是IE7-浏览器的特有属性。hasLayout是一种只读属性,有两种状态:true或false。当其为true时,代表该元素有自己的布局,否则代表该元素的布局继承于父元素。
触发hasLayout的条件:
position: absolute
float: left|right
display: inline-block
width: 除 “auto” 外的任意值
height: 除 “auto” 外的任意值 (例如很多人清除浮动会用到 height: 1% )
zoom: 除 “normal” 外的任意值 (MSDN) http://msdn.microsoft.com/worksh ... properties/zoom.asp
writing-mode: tb-rl (MSDN) http://msdn.microsoft.com/worksh ... ies/writingmode.asp
在 IE7 中,overflow 也变成了一个 layout 触发器:
overflow: hidden|scroll|auto ( 这个属性在IE之前版本中没有触发 layout 的功能。 )
overflow-x|-y: hidden|scroll|auto (CSS3 盒模型中的属性,尚未得到浏览器的广泛支持。他们在之前IE版本中同样没有触发 layout 的功能)
hasLayout更详细的解释请参见 old9翻译的 大名鼎鼎的 《On having layout》一文(英文原文:http://www.satzansatz.de/cssd/onhavinglayout.htm),由于old9博客被墙,中文版地址:
IE8使用了全新的显示引擎,据称不使用 hasLayout属性了,因此解决了很多深恶痛绝的bug。
2.letter-spacing和word-spacing
h1 {letter-spacing:2px} h2 {letter-spacing:-3px}
object.style.letterSpacing="3px"
letter-spacing : normal | length | inherit (检索或设置对象中的文字之间的间隔)
默认值是normal。length可以为负值。
word-spacing : normal | length | inherit (检索或设置对象中的单词之间插入的空隔)
p { word-spacing:30px; }
默认值是normal。length可以为负值。
3.Block formatting contexts (块级格式化上下文,后文简称为BFC)
CSS3里面对这个规范做了改动,称之为:flow root,并且对触发条件进行了进一步说明。
那么如何触发BFC呢?
float 除了none以外的值
overflow 除了visible 以外的值(hidden,auto,scroll )
display (table-cell,table-caption,inline-block)
position(absolute,fixed)
fieldset元素
需要注意的是,display:table 本身并不会创建BFC,但是它会产生匿名框(anonymous boxes),而匿名框中的display:table-cell可以创建新的BFC,换句话说,触发块级格式化上下文的是匿名框,而不是 display:table。所以通过display:table和display:table-cell创建的BFC效果是不一样的。
fieldset 元素在www.w3.org里目前没有任何有关这个触发行为的信息,直到HTML5标准里才出现。有些浏览器bugs(Webkit,Mozilla)提到过这个触发行为,但是没有任何官方声明。实际上,即使fieldset在大多数的浏览器上都能创建新的块级格式化上下文,开发者也不应该把这当做是理所当然的。CSS 2.1没有定义哪种属性适用于表单控件,也没有定义如何使用CSS来给它们添加样式。用户代理可能会给这些属性应用CSS属性,建议开发者们把这种支持当做实验性质的,更高版本的CSS可能会进一步规范这个。
BFC的特性:
1)块级格式化上下文会阻止外边距叠加
当两个相邻的块框在同一个块级格式化上下文中时,它们之间垂直方向的外边距会发生叠加。换句话说,如果这两个相邻的块框不属于同一个块级格式化上下文,那么它们的外边距就不会叠加。
2)块级格式化上下文不会重叠浮动元素
根据规定,一个块级格式化上下文的边框不能和它里面的元素的外边距重叠。这就意味着浏览器将会给块级格式化上下文创建隐式的外边距来阻止它和浮动元素的外边距叠加。由于这个原因,当给一个挨着浮动的块级格式化上下文添加负的外边距时将会不起作用(Webkit和IE6在这点上有一个问题——可以看这个测试用例)。
3)块级格式化上下文通常可以包含浮动
详见: W3C CSS2.1 - 10.6.7 'Auto' heights for block formatting context roots