likes
comments
collection
share

网页字体度量及渲染

作者站长头像
站长
· 阅读数 42

字体度量(Font Metrics)

字体度量是每个字体文件内的配置,如下图 1 和图 2 为用 FontForge 查看得到的 Catamaran 字体的度量属性。为了方便后文展示 Line Gap,此处手动将 Catamaran 字体的 HHead Line Gap 值从 0 调整为 500。

网页字体度量及渲染

图 1

网页字体度量及渲染

图 2

字体文件内,在没有设置 Typo metrics 优先(图 1 中 的 Really use Typo metrics 选项)时,对于 Windows 系统,浏览器读取 Win Ascent、Win Descent 值;对于 Mac / Linux 系统,浏览器读取 HHead Ascent、HHead Descent 值;Windows、Mac、Linux 系统均读取 HHead Line Gap 来确定行距,如下表 1 所示。

度量WindowsMacLinux
AscentWin AscentHHead AscentHHead Ascent
DescentWin DescentHHead DescentHHead Descent
Line GapHHead Line GapHHead Line GapHHead Line Gap

表 1:未设置 Typo metrics 优先

在设置了 Typo metrics 优先时,Windows 和 Linux 系统会读取 Typo Ascent、Typo Descent、Typo Line Gap 值,而 Mac 仍然会读取 HHead Ascent、HHead Descent、HHead Line Gap 值,如下表 2所示。

度量WindowsMacLinux
AscentTypo AscentHHead AscentTypo Ascent
DescentTypo DescentHHead DescentTypo Descent
Line GapTypo Line GapHHead Line GapTypo Line Gap

表 2:设置了 Typo metrics 优先

这也是为什么前端还原的 UI 稿在Windows 电脑、Mac 电脑、Linux 电脑展示样式可能有差异。

几个名词

x-height

在西文字体排印学中,x 字高(英语:x-height 或 corpus size)是指字母的基本高度,精确地说,就是基线和主线之间的距离,即小写字母 x 的高度。

ex

在西文的具体字体以及排版术语中,x 字高通常被称为一个 ex。

em

em 是字体排印学的计量单位,相当于当前指定的点数。em 最初表示的是字体中大写 M 的宽度及所用的尺寸。在 CSS 中,单位 em 是字体点数或英寸数在名义上的高度。

em 框(em-square)

em 框在字体中定义(也称为字符框( character box ))。实际字形可能比 em 框更高或更矮,font-size 的值确定了各个 em 框的高度。

行距(Line Gap)

下图 3 是 MILanPro 字体分别设置 Line Gap 为 0 和 Line Gap 为 500的渲染结果。浅灰色区域为行盒(line box),深灰色区域为文字内容区域(content area) 。Line Gap 为 0 时,内容区域撑开行盒;Line Gap 为 500 时,行距被均分为两份到内容区域上方和下方,然后才撑开行盒。

  <head>
    <meta charset="UTF-8">
    <style>
      @font-face {
        font-family : 'MILanPro_GAP0';
        src : url("MILanPro_GAP0.woff2") format("woff2");
      }
      @font-face {
        font-family : 'MILanPro_GAP500';
        src : url("MILanPro_GAP500.woff2") format("woff2");
      }
      .wrapper {
        padding : 0 40px;
        font-size : 100px;
        background-color : #eeeeee;
      }
      .gap0 {
        font-family : MILanPro_GAP0;
      }
      .gap500 {
        font-family : MILanPro_GAP500;
      }
    </style>
  </head>
  <body>
    <div class="wrapper gap0">
      <span style="background-color: #dddddd;">Xiaomi Mix</span>
    </div>
    <div class="wrapper gap500">
      <span style="background-color: #dddddd;">Xiaomi Mix</span>
    </div>
  </body>

网页字体度量及渲染

图 3

下面是一段HTML代码,一个 <p> 标签包含三个不同 font-family<span>。最终渲染如图 4,不同的字体使用相同的 font-size 导致不同的元素高度。测量到不同字体的不同高度:Helvetica:115px,Gruppo:97px,Catamaran:164px。原因就在字体本身。它的工作原理如下:

  • 字体定义它的 em-square(也被称作“EM size”或者“UPM”),在一个字体中,每个字符都放置在一个方块空间容器内。方块使用相对单位,通常为 1000 个单位,也可以是 1024 或 2048 等值。
  • 基于它的相对单位,设置字体的度量(ascet、descent、cap-height、x-height 等)。注意有些值是可以大于 em-square 的。
  • 在浏览器中,相对单位会被缩放以适应所需字体的大小。
<p>
  <span class="a">Ba</span>
  <span class="b">Ba</span>
  <span class="c">Ba</span>
</p>
p { font-size: 100px }
.a { font-family: Helvetia }
.b { font-family: Gruppo }
.c { font-family: Catamaran }

网页字体度量及渲染

图 4

下图 5 为 Catamaran 字体设置 font-size: 100px 时的各部分参数。首先计算得到字体文件中定义的

  • Ascet = 1100 单位 = 110px
  • Descent = 540 单位 = 54px
  • Line Gap = 500 单位 = 50px
  • 大写字母高(cap-height)= 68px(680单位)
  • 小写字母高(x-height)= 49px(485单位)

这意味着 Catamaran 字体设置 font-size: 100px 时,其在 1000 单位的 em-square 中使用 1100 + 540 个单位,得到实际高度 164px。此结果定义元素的内容区域(content-area) 。可以把 内容区域高度视为行内元素background 属性应用的区域。可计算得到:

  • 1ex = 小写字母高(x-height)= 49px
  • 1em = font-size = 100px(em 等于 font-size 而不是内容区域高度)
  • 内容区域(content area) = Ascet + Descent = 164px
  • 行高(line-height)= 内容区域(content area)+ Line Gap = Ascet + Descent + Line Gap = 214px

网页字体度量及渲染

图 5

八根线

本文,将字体的 Top line、Ascender line、Cap height line、Mean line、Middle line、Baseline、Descender line、Bottom line 称为字体的 8 根线。通常情况,这 8 根线垂直方向从上往下排列,同时这 8 根线决定了 8 个高度,如图 6 所示。行高(line-height)单独到下一章节介绍。

  • 上半行距:顶线(Top line)上悬线(Ascender line) 的距离
  • 上悬线距:上悬线(Ascender line)基线(Baseline) 的距离
  • 大写字高:大写字高线(Cap height line)基线(Baseline) 的距离
  • x 字高:主线(Mean line)到基线(Baseline) 的距离
  • x 半高:中线(Middle line)到基线(Baseline) 的距离
  • 下悬线距:下悬线(Descender line)基线(Baseline) 的距离
  • 下半行距:底线(Bottom line)下悬线(Descender line) 的距离

网页字体度量及渲染

图 6

Baseline 基线

基线Baseline)指的是多数拉丁字母排列的基准线,上图中黑色线即为基线。基线是其他七根线的基础,其他线的位置均以基线为基础确定。

Mean line 主线

主线Mean Line / Waist Line)指的是决定无升部小写字母字体大小的一条线,其与基线的距离称为**x 字高(x height)** 。

注意,字体设置的 x height 不一定与渲染的 x 字母的实际高度相同。MiLanPro 为例,如图 7、8、9 所示,x 字母真实高度为 526,而字体设置的 x height 值为 480。MiLanPro 字体的 主线与字母 x 上边缘并未齐平。

网页字体度量及渲染

图 7

网页字体度量及渲染

图 8

网页字体度量及渲染

图 9

Middle line 中线 / x 半高线

中线(Middle line) 通常理解为字母的中间位置,高度是主线高度的一半,也就是 x height 的一半。

Cap height line 大写高线

大写高线(Cap height line) 指的是决定大写字高的一条线。大写字高(Cap height) 是指某种字体中,位于基线(baseline)以上的大写字母的高度。尤其指相对平顺的字母“H”和“I”的高度。因为圆型的字母 O 和尖形字母 A 等,在设计中为保持视觉观感,其高度会有上下浮动(Overshoot)。

Ascender line 上悬线

上悬线(Ascender line) 指的是决定字体升部的一条线。升部Ascender)是指一个字体的字母中向上超过主线笔画的部分,也就是比x字高还要高的部分,是字体设计中一个重要的组成部分。下图 10 中红色部分即为升部。注意,西文字体排印学中,升部Ascender)只是指红色部分主线到上悬线(Ascender line) 的距离;但在字体文件中,上悬线距(Ascent) 表示的是字体基线到上悬线(Ascender line) 的距离。

网页字体度量及渲染

图 10

Descender line 下悬线

下悬线(Descender line) 指的是决定字体降部的一条线。降部Descender)在西文字体排印学中指的是一个字体中,字母向下延伸超过基线的笔画部分,也称为下延部。下图 11 中红色部分即为降部。注意,西文字体排印学中,降部Descender)只是指红色部分主线到下悬线(Descender line) 的距离;但在字体文件中,下悬线距(Descent) 表示的是字体基线到下悬线(Descender line) 的距离。

网页字体度量及渲染

图 11

Top line 顶线

顶线(Top line) 是决定字体上半行距位置的一条线。顶线与上悬线之间的距离为上半行距,对应字体文件中 Line Gap 的值取半。

Bottom line 底线

底线(Bottom line) 是决定字体下半行距位置的一条线。底线与下悬线之间的距离为下半行距,对应字体文件中 Line Gap 的值取半。

字体渲染

line-height

line-height 属性

属性介绍
normalTells user agents to set the used value to a "reasonable" value based on the font of the element. The value has the same meaning as <number>. We recommend a used value for 'normal' between 1.0 to 1.2. The computed value is 'normal'. W3C 中的描述不清楚,实际 line-height 由字体度量和 font-size 决定,与其他无关。
<length>长度值The specified length is used in the calculation of the line box height. Negative values are illegal.line-height 由长度值决定,子元素默认继承长度值。
<number>数字The used value of the property is this number multiplied by the element's font size. Negative values are illegal. The computed value is the same as the specified value.line-height 由 <number> 和 font-size 相乘得到,子元素默认继承 <number> 而不是乘积。
<percentage>百分比The computed value of the property is this percentage multiplied by the element's computed font size. Negative values are illegal.line-height 由 <percentage> 和 font-size 相乘得到,子元素默认继承乘积而不是 <percentage>

line-height: normal 时行高的计算公式

行高 = 上半行距(红色) + 上悬线距(橙色)+ 下悬线距(粉色)+ 下半行距(青色)

回看图 6,font-size: 100px,基于上面的公式,得到:

行高 = 25px + 110px + 54px + 25px = 214px

line-height 中 1em、100% 和 1 的不同

如下代码块和对应的图 12 所示(字体采用 Catamaran 字体):

  • 当 line-height 的值有单位时,子元素继承的是父元素计算之后的值,即在父元素上计算
  • 当 line-height 的值为百分比时,子元素继承的是父元素计算之后的值,即在父元素上计算
  • 当 line-height 的值无单位时,是继承值(缩放因子)而不是计算值,即在当前子元素上计算

    line-height: 1em; line-height: 1em; line-height: 1em; line-height: 1em; line-height: 1em; line-height: 1em;
    line-height: 100%; line-height: 100%; line-height: 100%; line-height: 100%; line-height: 100%; line-height: 100%;
    line-height: 1; line-height: 1; line-height: 1; line-height: 1; line-height: 1; line-height: 1; line-height: 1;

网页字体度量及渲染

图 12

vertical-align

vertical-align 属性

下表为 vertical-align 对应的可选值。

属性介绍
topAlign the top of the aligned subtree with the top of the line box.元素顶部(顶线)与父元素顶部(顶线)对齐。
text-topAlign the top of the box with the top of the parent's content area.元素顶部(顶线)与父元素内容区域顶部(上悬线)对齐。
superRaise the baseline of the box to the proper position for superscripts of the parent's box. (This value has no effect on the font size of the element's text.)Raise by the offset appropriate for superscripts of the parent’s box. The UA may use the parent’s font metrics to find this offset; otherwise it defaults to raising by one third of the parent’s used font-size.以父元素基线为初始位置,元素基线向上偏移,偏移量从字体度量读取或直接计算三分之一父元素的 font-size 值,本属性对 font-size 无影响。
middleAlign the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.元素中线/中间位置与父元素中线对齐。
baselineAlign 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.默认值,元素基线与父元素基线对齐。
subLower the baseline of the box to the proper position for subscripts of the parent's box. (This value has no effect on the font size of the element's text.)Lower by the offset appropriate for subscripts of the parent’s box. The UA may use the parent’s font metrics to find this offset; otherwise it defaults to dropping by one fifth of the parent’s used font-size.以父元素基线为初始位置,元素基线向下偏移,偏移量从字体度量读取或直接计算五分之一父元素的 font-size 值,本属性对 font-size 无影响。
text-bottomAlign the bottom of the box with the bottom of the parent's content area.元素底部(底线)与父元素内容区域底部(下悬线)对齐。
bottomAlign the bottom of the aligned subtree with the bottom of the line box.元素底部(底线)与父元素底部(底线)对齐。
<percentage>百分比Raise (positive value) or lower (negative value) the box by this distance (a percentage of the 'line-height' value). The value '0%' means the same as 'baseline'.以父元素基线为初始位置,以行高为基础值,元素基线向上(正值)或向下(负值)偏移。
<length>长度值Raise (positive value) or lower (negative value) the box by this distance. The value '0cm' means the same as 'baseline'.以父元素基线为初始位置,元素基线向上(正值)或向下(负值)偏移。

如图 13 所示为 vertical-align 各属性对应的对齐位置。

网页字体度量及渲染

图 13

拓展问题

  1. 文本设置 vertical-align: middle 后是不是居中的?

不一定。

vertical-align: middle 时,子元素中线/中间位置与父元素的中线(Middle line) 对齐。由图 5 可知,需要子元素和父元素的字体度量均满足

上半行距 + 上悬线距 - x 半字高 = x 半字高 + 下悬线距 + 下半行距

才能达到完全居中。又因为上半行距下半行距 相等,换算得到

上悬线距 - 下悬线距 = x 字高

时,文本居中。

  1. 无法修改字体度量的情况,如何让内容居中?

提示:从行距(Line Gap)入手。

答案由大家思考。

字体选择与合成

字重

每个字体集可以由多个样式变体(常规、粗体、斜体)和每种样式的多个粗细(字重)组成。

网页字体度量及渲染

图 14

上图中的字体提供了三种不同字重的字体(黑色 A):

  • 400 (regular)
  • 700 (bold)
  • 900 (extra bold)

所有其他中间变体(灰色 A)由浏览器自动映射到最接近的变体。

CSS Font Matching Algorithm

When a weight is specified for which no face exists, a face with a nearby weight is used. In general, bold weights map to faces with heavier weights and light weights map to faces with lighter weights.

翻译一下:当前字重不存在时,会自动匹配接近的字重。 通常粗体字重会匹配更粗的字体,常规字重会匹配更细的字体。

字体样式

上文解释了缺少字重时浏览器的处理策略。那如果加载的 web 字体只定义了常规样式,而某个元素设置了font-styleitalic该怎么办?

  • 如果没有完全匹配的字体,浏览器将替换最接近的匹配项
  • 如果未找到样式匹配(例如,在上面的示例中未声明斜体变体),则浏览器会合成自己的字体变体

下面代码提供了 400 和 700 字重,最终结果如图 15,左侧为字体所有字重和样式对应的渲染,右侧为实际浏览器渲染结果。

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: url('/fonts/awesome-l.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 700;
  src: url('/fonts/awesome-l-700.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

网页字体度量及渲染

图 15

字体库

谷歌字体库

所有 Google Font 字体都是开源的,是免费的,可以商用。

小米字体

目前提供小米兰亭Pro(MI Lan Pro)、MiSans、MiType、MiType 等宽字体(MiType-Mono)、思源宋体(Source Han Serif)5 种字体。

参考链接

  1. Exploring x-height & the em square: fonts.google.com/knowledge/c…
  1. Deep dive CSS: font metrics, line-height and vertical-align: iamvdo.me/en/blog/css…
  1. 揭开 baseline & line-height & vertical-align 的面纱:paddywang.github.io/demo/list/c…
转载自:https://juejin.cn/post/7242145254056362039
评论
请登录