内联元素的一些探究
本文依然是对《CSS世界》这本书中的一些知识点进行探究和实践。内联元素在CSS中极为重要,块级元素负责结构,内联元素负责内容,而CSS又是为图文展示而设计,因此显得尤为重要。同时多个属性混合在一起共同作用又会产生较为复杂的结果,比较典型的就是line-height
和vertical-align
,以及“幽灵空白”(CSS文档中叫strut)产生的一些现象了。
文中也将从这三个方面去入手,实践一些现象产生的原因。
幽灵空白
“幽灵空白”这个概念并非没有意义,内联元素中产生的很多看似很难解释的现象其实很多都和这个“幽灵空白”息息相关。
证明幽灵空白存在
line box starts with a zero-width inline box with the element’s font and line height properties. We call that imaginary box a “strut.”
上面是一段对strut的描述,书中将其称为幽灵空白,表现为看不见摸不着,但却真实存在,可以用一段代码证明其存在。
1 | <div> |
css代码如下
1 | div { |
从上图可以看出来,其中并没有内容,内部的span
宽高也都是0,但是div
的高度却并不为0,而是20.8px,即可以认为span
元素前面还有一个宽度为0的空白字符,那么都可以解释通了。
Line boxes that contain no text, no preserved white space, no inline elements with non-zero margins, padding, or borders, and no other in-flow content (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes
同样还要注意,这里display
要指定为inline-block
,否则按照上述文档的描述,高度会被视为0
这里为什么是20.8px呢?根据我的理解,这里的20.8px即内容区域(content area),即内联盒模型中的一个不可见区域。根据《css世界》作者的理解与实践,可以将其理解为文本选中背景色区域。
这里内容区域是由font-family
和font-size
共同决定的,可以做一个测试,比较设置font-family: simsun
和不设置时的区别。(默认为微软雅黑)
1 | div { |
设置之后,高度变为18.4px
即内容区域的高度和字体相关。当然这里还是有一个疑惑,设置宋体之后,内容区域应该和em-box
相同,按照默认16px,高度应该是16px而非18.4px。这里暂未找到原因。
line-height
line-height
属性可以说是内联元素的基石
决定非替换元素的高度
决定高度要分成两部分来讲,对于替换元素和非替换元素来讲是不同的
非替换元素
对于非替换元素(替换元素比如img)的内联元素来将,其高度是由line-height
决定的。比如说一个<div></div>
是高度为0,当写上几个字之后就有了高度,但是这里的高度并非由font-size
决定,而是由line-height
决定的。可以用代码测试一下。
1 | <div> |
css代码如下
1 | .test1 { |
可以看到,上面font-size
为16px的只有border撑起来的2px,而下面的line-height
为16px的则是一共18px的高度。由此可以得出结论,内联元素的高度是由line-height
来决定的。
替换元素
对于替换元素来讲,比如说图片,设置其容器的line-height
并不会影响到图片,但是由于图片为内联元素,前面也然会有一个幽灵空白,所以会造成容器被撑大的现象,但并未影响到图片。
只有在非替换元素下,才能决定高度,在混合情况下,比如说图文混排时,则只能决定最小高度,不仅是替换元素不受line-height
影响,同时也有vertical-align
的影响。
行距
行距是内容排版上很重要的一点,但是由于平时开发中,也都是看着差不多就行了,并没有对其中的实现有所了解。这里也通过行距来进一步理解line-height
在内联元素中重要的作用。
行距在css里是分成上半部分和下半部分的,即第一行文字上面也是会有一半行距的。行距的计算公式即行距 = 行高 - em-box
,简单讲就是行距 = line-height - font-size
。
这里要注意一点,内容区域和em-box
不一样,内容区域受font-family
和font-size
共同决定的,而em-box
只受font-size
决定,所以你会发现,设置不同的字体,同样的font-size
,按照公式计算的话行距是一样的,但是肉眼看到的行距似乎却并不一样。
但是有一个字体例外,宋体的内容区域和em-box
的区域是等同的。
1 | <div class="test"> |
css代码如下
1 | .test { |
行距即上下两边黄色的部分,这里可以做一个测试,将字体改为微软雅黑之后
可以明显的看到,内容区域的高度并不一致。
内联元素垂直居中
单行文字
这里要纠正一个之前一直犯的错误,单行文字垂直居中只需要line-height
即可,并不需要画蛇添足加一个height
。
举个例子,一个高度为50px的标题垂直居中
1 | .title{ |
并不需要注释掉的那一行
多行文字或替换元素
这里需要line-height
和vertical-align
共同作用
1 | <div class="box"> |
css代码如下
1 | .box { |
这里需要解释一下原理
- box里的width和margin共同作用外部容器水平居中
- box里的line-height决定容器高度
- content里的display很关键
1 这里重置了外部line-height大小,不能指定为block等块级元素,需要保持内联元素特性,因为需要使用vertical-align属性
2 同时产生行框盒子及幽灵空白。这里需要幽灵空白被box的line-height作用,撑开外部容器。 - vertical-align: middle是为了调整对其方式,默认向基线对齐,需将其改成近似居中对齐
line-height的大值特性
大值特性,其实内在原因同样是由于幽灵空白的作用。举个例子
1 | <div class="box box1"> |
css代码如下
1 | .box { |
可以看到box容器高度都是96px,那么解释一下原因,还是由于幽灵空白,span
元素前面可以假设把它加上一个x匿名内联元素。
加入是外部设置line-height
为96px,那么则是作用到了x这个幽灵空白上,倘若是子元素设置了line-height
,则是作用到了子元素的行框盒子上。整体行框盒子由最大的决定,因此还是96px。
如果想避免幽灵空白的干扰,将上面注释掉的代码恢复,即设置inline-block
创建一个独立的行框盒子,就能将里面的子元素不受干扰。同时满足大值特性
vertical-align
说到这个属性,就要提到基线,这也是很多现象产生的原因,比如说vertical-align: middle
其实是近似垂直居中。
而这近似垂直居中又导致了很多现象的出现,比如说很常见的一个布局,一行字加上一个下拉符号
设置的都是20px大小,而且也使用了vertical-align: middle
,但是最后的结果整个容器总是要大于20px,原因就和基线的定义有关了,如下图所示
那么基线的定义就是字母x的下边缘,middle则是指基线往上1/2的x-height的位置,可以理解为x中间的那个交点。看似没有什么问题,但实际上问题就由此产生,每个字体在行内盒子的位置是不一样的,上面也比较了微软雅黑和宋体两个字体的差异,可以明显发现微软雅黑字体会下沉,那么也就导致了middle和实际的中线位置会往下偏一点。那么这个偏一点具体偏多少由font-size
的大小决定,越大则下沉的效果越明显。所以实现真正意义上的居中是很困难的。
拿一个作者博客的例子
可以很明显的看到,确实如我上文所说,要想实现真正意义上的垂直居中,可以设置font-size
为0,这样x就缩小为一个点,就能实现垂直居中效果,当然开发中并非一定要真正实现这种,一般情况下也看不出来
单行文本高度不等于行高现象
1 | <div> |
css代码如下
1 | div { |
可以看到如图中所示,高度并不为32px,出现这一现象也是由于vertical-align
以及幽灵空白作用的结果,理解这一现象本质,有助于理解内联元素。
这似乎与上面行高决定非替换元素的高度这一观点相矛盾,其实并非如此,很多现象都是很多属性共同作用的结果。这里产生的原因就是子元素设置了font-size
属性,导致和父元素字体大小不同,而内联元素又是和基线对齐,导致错位。
我们可以在span前面加上一个x作为匿名内联盒子,在span里面加上一个x作为内联盒子
可以看到,本来匿名内联盒子的x位置好好的,但是由于内联盒子字体太大了,导致为了基线对其,而将文字上移,就把父级容器撑开了,导致高度大于32px也就是这个原因。
解决方案很简单,原因是font-size
产生的,自然可以从字体大小上改动,指定父元素的font-size
为24px与子元素相同,就能使高度为32px
图片底部留有间隙现象
这个现象可以说是从我刚开始学css起就遇到过了,结果之一也就不了了之了,只知如何解决,却不理解产生这种现象的原因。
1 | <div class="box"> |
css代码如下
1 | .box { |
可以看到,按照代码来看,应该是容器被图片撑开,然后是96px才对,然而实际确实100px,产生间隙的原因很多情况下都是line-height
,vertical-align
,幽灵空白
造成的,此处也不例外
这里和前面一样加上x,并添加上背景色辅助观察。可以很明显地看到产生间隙的原因,内联元素中,图片的基线按照下边缘来决定。
因此,图片下边缘和x下边缘对齐,那么下边的间隙就是半行距,没错,间隙就是半行距撑开的。既然知道了产生的原因,那么解决起来就很简单了,消除半行距即可。比如让父元素line-height足够小,另行距为0或者是负值,即可解决。当然,也可以直接消除幽灵空白,将图片块状化,幽灵空白就消失了。或者改变对齐方式也可以解决。
总结
css看似简单但也确实是有很多值得去探讨的地方,理解内在的原理也许才能更好的设计出更加合理的布局。
- 感谢你的欣赏!