本文首发于[Godfery的博客]。
感谢Godfery为大家贡献的优秀文章,大家可以通过点击本文下方的阅读原文来访问Godfery的博客
这张图展示的是8种不同的字体,其中第一、第二个分别为 font-awesome图标、自定义的字体图标,其余字体依次为Avenir、Trebuchet MS、Arial、Helvetica、Hiragino Sans GB、STXihei。(源码地址:https://codepen.io/hiyangguo/pen/VXqQMB)
这些字符的font-size:100px,但是占的高度却不一样。有的是 100px,有的大于 100px。另外可以看出,垂直方向并没有居中对齐。 这篇文章主要研究:
字体度量
要弄明白上面问题的答案,需要先从字体说起:
我们拿出其中Avenir、Helvetica、Hiragino Sans GB三种字体进行分析
由上图可知,在我们设置 font-size:100px 时,文字所占的高度分别为 137px、 115px 和 100px。
感觉有点懵啊。怎么 font-size:100px ,可是高度却由于字体不同,而不一样了呢? 在字体设计中一个字符所在的空间容器称为EM Square(也被称作“EM size”或者“UPM”)。
在传统的金属字模中,这个容器就是每个字符的实际金属块。每个字符的高度是统一的,这样每个字模可以整齐地放进行和块中(如下)。
字体的定义规则
字体的设置
这是一张详解字体设置的图例,图中各个属性的意义:
字符所占高度的计算
所以在了解了上面的概念以后,就可以解答为什么在 font-size:100px 的时候行高却不一样的问题。
首先,先下载一个专业的字体软件FontForge,这个软件运行在xquartz上,所以要两个都要装。
百度云通道( https://pan.baidu.com/s/1GqI-n39GkFQWsNZ8vWKMGg#list/path=%2F )
安装后我们以 Avenir 字体为例进行分析。
注:浏览器使用HHead Ascent/Descent值(Mac)和Win Ascent/Descent值(Windows),并且这些值可能不同。
这意味着 Avenir 字体在 1000 单位的 EM size 中使用了 1000 + 366 个单位,也就是说 font-size:100px,其高度为 100px * (1000 + 366 ) ≈ 137px。 这个计算高度定义了 元素内容(Content area)高度 也就相当于 background 属性。
CSS box models
接下来我们深入的研究一下,CSS box models。你可能不知道什么CSS box models,不过说出来你可能不信,在实际工作当中恐怕你最常见的就是CSS box models。
Block Box/Containing Box (块盒子/包裹盒子)
比如有一段简单的文字,就有可能会有一些列的 box 。那么这个段落被称为 Containing Box ,之所以这么命名,可能是因为他包含了很多 box 吧。(呵…)当然你也可以称之为 Block Box,因为他就是一个块。简单来说Containing Box和Block Box其实是一个东西。
Inline Box (内联盒子)
在段落内部,有很多的 Inline Box。 这些 Box 不会像 Block Box 那样形成新的一⾏。
在上面的例子中, <em/> 标签包裹的 斜体元素 就是一个典型的 Inline Box。
Anonymous Inline Box (匿名内联盒子)
在段落内部,那些没有标记的Inline Box 则成为 Anonymous inline Box。
Line Box (行盒子)
所有Inline Box在Containing Box紧挨着排列,则会形成 Line Box。需要注意的是,Line Box是没办法直观看到的。
Content area
Content area 是围绕⽂文本的隐形框。 而且在字体度量这一小节我们也证明过了,它的高度由font-size决定。
更详细的定义及说明可以访问 CSS 规范2.1 中关于 视觉格式化模型(Visual formatting model)一节进行阅读。
地址:
视觉格式化模型
http://www.ayqy.net/doc/css2-1/visuren.html
9 Visual formatting model
https://www.w3.org/TR/CSS2/visuren.html
Inline Box 与 Line Box
Inline Box 如何影响 Line Box
Line box 的高度由 Line Box 中最⾼的 Inline Box(或Replaced Element)确定。 最⾼的 Inline Box 可以是⼀个 Anonymous Inline Box。
也可能是一个增加了line-height的 Inline Box。 由于增加了 line-height ,所以这个它会比其它的 box 更高。
可能是⼀个更⼤的 font-size 的 Inline Box,这使得这个 Inline Box ⽐其他 Inline Box更高。
由于浏览器器的不同,它也可能受到上标或下标的影响。 因为有些浏览器以影响Line box的方式渲染上标元素。
我们可以通过设置 <sup/>、<sub/> 的 line-height 为 0 来解决这个问题。
Inline Box 可能受到 Replaced Element(如:<img/>、<input/>、<svg/>) 的影响。
Inline Box 撑破 Line Box
正如我们所看到的, Line Box 将增加所有行内 Inline Box 的⾼度。
但是,有时候 Inline Box 的一部分会撑破 Line Box 的顶部或底部。例如一个拥有padding、margin、border 的 Inline Box 。由于 Inline Box 不能设定高度(设了也白设)。因此会在元素的上方和下方显示padding、margin、border,但并不会影响 Line Box。 注意:对于Replaced Element、inline-block行内元素padding、margin、border都会增加高度,所以Line Box 的高度也会受到影响。
浏览器将按照文档的先后顺序呈现 Line Box。 所以, 后续行上的 border 可能会覆盖上⼀行的 border和文本。
参考文章 行内元素垂直方向的layout 深入了解CSS字体度量,行高和vertical-align FontForge 与字体设计 - EM Square Deep dive line-height