理解 CSS 中的 line-height 和 vertical-align

文章地址:https://github.com/afishhhhh/blog/issues/4

一个例子

《理解 CSS 中的 line-height 和 vertical-align》 image

div { background: #eee; border: 1px solid #000; box-sizing: border-box; }
<div><img src="./image.png" alt=""></div>

在图片中可以看到 <img> 与外层的 <div> 存在一个间隙,这是因为浏览器认为每一个 line box 的起始位置都存在一个宽度为 0 的,没有任何字符的 匿名 inline box(下文会提到的 strut),也就是说这个 匿名 inline box 的高度会影响整个 line box 高度的计算。

在这个例子中 <img> 作为一个可替换的行内元素,在默认情况下他的底边与父元素的 baseline 对齐。而这个父元素的 baseline 所在的位置就是父元素中字母 x 底端所在的位置。如下图所示:

《理解 CSS 中的 line-height 和 vertical-align》 demo

上文所说的 strut 其实就相当于一个不可见的字母 x,父元素的基线就是 strut 的基线所在的位置。而 strut 本身是具有 line-height 的,所以就导致图片底部多了一段间隙。

总结一下存在间隙原因:

  1. strut 存在 line-height
  2. vertical-align 默认值为 baseline

对应的解决方案:

  1. 修改 strutline-height,因为 strutline-height 不是能够直接设置的,所以需要设置父元素的 line-height,然后让 strut 继承,或者修改 font-size
  2. vertical-align 设置为其他值

IFC

《理解 CSS 中的 line-height 和 vertical-align》 image

<div>我是一个匿名 inline box <em>我是一个 inline box</em> 我是另一个匿名 inline box</div>

IFC 中有两种盒子:inline-level boxline box。多个 inline-level box 组成了一个 line box

line box 高度计算

  1. 浏览器会计算 line box 中每一个 inline-level box 的高度,对于不同的 inline-level box 计算方式有所不同。如果是一个替换元素,高度由其 margin box 决定,如果是一个非替换元素,高度由它的 line-height 决定。
  2. line box 中所有 inline-level box 的最高点以及最低点决定了它的高度(该计算包括了 strut 的高度,后文 line-height 中提到 strut)。

以上文的图片作为例子:

<img> 所在的 line box 最高点是图片的顶部,最低点是 strut 的底部。<img> 作为一个 inline-level box,它的高度就是图片的高度,而 strut 其实就是个普通的文字,再加上 vertical-align: baseline 的作用,最终撑开了整个 line box。多个 line box 堆叠起来就撑开了父元素的高度,在这里只有一个 line box,撑开了 <div> 的高度。

  1. 非替换元素的的 marginpadding 以及 border 并不会影响 line box 高度的计算。当一个 inline-level boxline-height 小于 content area 的时候,line box 的高度就会小于 content arealine box 的高度与 content area 是没有关系的),此时元素的 background 以及 padding 等就会溢出到 line box 之外。

以下代码可以说明这个问题:

div {
    background: #eee;
    border: 1px solid #000;
    box-sizing: border-box;
    font-size: 50px;
    line-height: 10px;
}
span {
    background: red;
    margin: 10px;
    padding: 10px;
}
<div><span>xxx</span></div>

《理解 CSS 中的 line-height 和 vertical-align》 image

line-height

W3C 中对于 line-height 的解释是这样的:

On a block container element whose content is composed of inline-level elements, ‘line-height’ specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each 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.”

我的简单理解是,对于由行内元素组成的块级元素而言,line-height 决定了 line box 的最小高度,浏览器会假定每一个 line box 以一个宽度为 0 的 inline boxstrut)开始,而这个 strut 从父元素继承到 font 以及 line-height。(issue 开头的例子就是 strut 造成的)

  • normalline-height 的默认值,W3C 对它的定义是一个介于 1.0 到 1.2 的数值(并没有看懂)。根据另一篇文章的解释,normal 与字体本身有一定关系。
  • line-height 并不是两条 baseline 之间的距离。

line-height 的值推荐使用数值,而不是使用 em 单位,因为 em 单位会根据从父元素继承到的 font-size 来计算行高。

vertical-align

W3Cbaseline 以及 middle 的定义如下:

baseline: Align the baseline of the box with the baseline of the parent box. If the box does not have a baseline, align the bottom margin edge with the parent’s baseline.

元素基线与父元素基线对齐,如果元素没有基线,比如 <img>,则使用 margin 底边与父元素基线对齐。

middle: Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.

元素的垂直中点位置与父元素的基线加上一半 x-height 的位置对齐。

参考

https://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-height/
https://zhuanlan.zhihu.com/p/25808995
https://www.w3.org/TR/CSS2/visudet.html#inline-box-height

    原文作者:afishhhhh
    原文地址: https://www.jianshu.com/p/1d9bd8959711
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞