题图来自 http://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align
为什么同样的 font-size ,文字高度不一样?
每个字体在设计的时候,都是基于一个 EM Square,这是活字印刷中字模的高度。
在数字化字体中,em 是空间的数字化定义总量。在OpenType字体中,UPM或em大小通常是1000单位。在TrueType字体中,UPM约定是2的幂,通常是1024或2048。
实际情况中,许多字体的内容高度其实是比 em box 要大的。
同是 font-size: 30px
情况下,此处的 Noto Sans JP 的字体空间就比 Kosugi Maru 要高。而且在字体框内,垂直方向上还有留白。
垂直方向留白大小的计算公式,可以由字体文件中的定义得到:
internal leading = ascent - descent - EM_size
代码片段
可以在这个 fiddle 里看到结果。
使用 canvas 度量文字宽度
|
不过此 API 是拿不到字符的高度的。就有一些比较黑的方法来估算字体的内容高度,例如使用大写字母 'M' 的宽度作为内功高度的近似。这些技巧其实都与字形设计的惯例有关,在拉丁字母中,'M' 是字形最为饱满和方正的字符,高度与宽度近似。
不过明显这个惯例对于以上两个日文字体并不适用。
汉字因为字形多数为饱满的方块字,用宽度去估计内容高度其实更容易,例如 '人' 和 '口' 就很好用。
创建临时 dom 元素用于度量高度
能拿到更全的字形盒信息
|
稍微不那么简单但准确的方法
基于 canvas 的 FontMetrics
FontMetrics 这个库,先清空 canvas,将文字渲染至 canvas 上,然后逐行统计 canvas 上的像素,由此可以知道文字的上下内容边界,再与 font size 换算,便可以得到字符的高度。
opentype.js
opentype.js 是一个优秀的解析 OpenType 字体的 js 库。以 ArrayBuffer 传入字体的数据,解析出所有 OpenType 标准数据,完全可以基于此写出符合自己需求的排版引擎。
|