字体到底是什么:从码位到轮廓
本系列其余页面都在「拨字体里的开关」「量字体的高度」——但字体本身到底是什么?一句话:字体文件 = 一组字形(glyph)轮廓 + 一张编码表(cmap)。你在 HTML / 内存里存的从来不是「字」,而是码位(character / code point);cmap 负责把码位查成字形编号;字形编号指向一组控制点;浏览器照这组点描出一条贝塞尔轮廓(outline)填成黑色——这才是你最终看到的那个字。
下面这个 demo 把流程最右端的 outline 拆解开来:这是一个小写 o 的字形,它不是像素,而是少数几个控制点连成的两条闭合曲线——外轮廓 + 里面那圈反向的「窟窿」(counter)。拖动任意一个点,字形即随之变形。字体文件里存储的,正是这些点的坐标。
1 · 五个术语的区分
| 词 | 是什么 | 例子 / 关键点 |
|---|---|---|
| character — 字符 / 码位 | 抽象的「字」,Unicode 给它一个码位。存在你文件、数据库、内存里的就是它。 | 'o' = U+006F;'字' = U+5B57。和长什么样无关。 |
| glyph — 字形 | 字符呈现出来的样子。一个字符可以有多个字形(本系列的 feature 开关就是在它们之间切换),多个字符也能合成一个字形(连字 fi)。 |
o 的正常体 / 小型大写 / 老式数字… 都是不同 glyph。 |
| cmap — 编码表 | 字体文件里的一张表,把码位 → 字形编号。换一份 cmap,同一段码位就画成完全不同的字形。 | 字体反爬正是利用这一点:故意错排 cmap。 |
| outline — 轮廓 | 字形的几何定义——一组 on-curve / off-curve 控制点连成的闭合贝塞尔曲线。不是位图,所以能无级缩放。 | TrueType 用二次贝塞尔,CFF/OTF 用三次。外轮廓 + 反向内轮廓(counter)。 |
| em-square — UPM 坐标系 | 所有控制点坐标所在的方格,边长 = units-per-em(常见 1000 / 2048)。baseline 是 y=0。 | 渲染时整张方格缩放到 font-size——详见 字体度量。 |
字体文件(.ttf / .otf)= 一组 outline(glyf / CFF 表)+ 一张 cmap + 度量(hmtx / hhea)+ 一系列排版规则(GSUB / GPOS,即本系列拨的那些 feature)。
这页是地基,往两个方向接上:坐标点乘上 font-size 怎么决定元素高度与 line-height: normal——见 字体度量:为什么 100px 不是 100px;cmap 那张「码位 → 字形」表被恶意错排当锁用——见
把字体当锁:字体反爬。中间那些 font-variant-* / font-feature-settings 开关,拨的就是 GSUB 表里「同一码位换一个字形」的规则。轮廓画好后怎么填到像素网格、边缘怎么抗锯齿(subpixel vs grayscale)——见
字形如何变成像素。
2 · 相关链接
- What Is a Font? · Design with FontForge——designwithfontforge.com。本页蓝本。从 FontForge 作者视角讲清字体 = 字形轮廓集合 + 编码:character vs glyph、cmap 映射、控制点描出的轮廓、em / UPM 坐标系。
- What is a Glyph in Typography?——fontfabric.com。character vs glyph 的基础:一个字符可对应多个字形,本系列的 feature 开关就是在这些字形间切换。
- Bézier curve · MDN Glossary——developer.mozilla.org。on-curve 锚点 + off-curve 控制点怎么定义一段曲线;字形轮廓就是一串首尾相接的贝塞尔段。
- cmap — Character to Glyph Index Mapping Table——learn.microsoft.com。OpenType cmap 表的官方规范:码位如何查成 glyph index,以及为什么换一份 cmap 就能把同一段文本画成别的字形。