字样或字体家族用于归组相关字体面。字体面具有字重、样式和字宽等属性。字形是为字符或字符序列选择并渲染出的形状。
浏览器按字符进行字体选择。因此,一个段落可以为拉丁字母使用一个字体家族,为 CJK 字符使用另一个字体家族,并为表情符号使用表情符号字体。
构建字体家族栈 #
font-family 是由字体家族名称和通用字体家族组成的有序列表:
body {
font-family:
"Example Sans",
"Noto Sans",
system-ui,
sans-serif;
}包含空格的字体家族名称应使用引号。由于不同操作系统提供的本地字体不同,应以通用字体家族作为字体栈的末尾项。
通用字体家族包括 serif、sans-serif、monospace、cursive、fantasy、system-ui、ui-serif、ui-sans-serif、ui-monospace、ui-rounded、emoji、math 和 fangsong。较新的通用名称在不同环境中的支持情况不同,因此应保留一个范围较广的最终回退项。
对于每个字符,浏览器会考虑可用的字体面、请求的样式、字重和字宽;如果选定的字体面缺少相应字形,则回退到其他字体。回退可能导致同一行内的度量发生变化,因此应测试生产内容所包含的文字系统。
声明可下载的字体面 #
@font-face 将字体家族和字体面范围关联到一个资源:
@font-face {
font-family: "Example Sans";
src: url("/fonts/example-sans-latin.woff2") format("woff2");
font-style: normal;
font-weight: 400 700;
font-display: swap;
}该声明不会应用字体。后续的 font-family 声明才会选择它。
除非文件包含相应的可变轴,否则应分别声明斜体和正体字体面:
@font-face {
font-family: "Example Sans";
src: url("/fonts/example-sans-italic.woff2") format("woff2");
font-style: italic;
font-weight: 400 700;
font-display: swap;
}准确的描述符可以在真实字体面存在时,防止浏览器合成粗体或斜体。
只有在合成粗体、斜体或小型大写字母会违背设计要求,并且所有必需的字体面都可用时,才应设置 font-synthesis: none。否则,当选定字体缺少请求的字体面时,合成可以保留强调效果。
理解 Web 字体格式 #
现代网站应优先使用 WOFF2。它使用针对 Web 传输设计的压缩来封装 OpenType 或 TrueType 字体数据。
| Format | Role |
|---|---|
TrueType (.ttf) | 使用 TrueType 轮廓的桌面和平台字体格式 |
OpenType (.otf) | 支持多种轮廓和排版技术的字体容器 |
| WOFF | 带有压缩和元数据的 Web 容器 |
| WOFF2 | 使用更强压缩的新一代 Web 容器 |
| EOT | 历史上的 Internet Explorer Web 格式 |
| SVG fonts | 已废弃的文本字体机制;SVG 仍适用于图标和图形 |
格式转换不会授予再分发权。在自行托管或子集化字体之前,应核实字体许可证。
有意使用可变字体 #
可变字体在一个文件中存储一系列设计。已注册的轴包括字重(wght)、字宽(wdth)、光学尺寸(opsz)、倾斜度(slnt)和斜体(ital)。
@font-face {
font-family: "Example Variable";
src: url("/fonts/example-variable.woff2") format("woff2");
font-weight: 300 800;
font-stretch: 75% 125%;
font-style: normal;
}对于已注册的轴,应使用 font-weight 和 font-stretch 等高级属性。font-variation-settings 适用于自定义轴或精确的底层控制。
可变字体面参与与静态字体面相同的字体家族匹配算法。请求值位于声明的轴范围内时,会选择插值实例。当请求值位于范围之外时,匹配会使用最接近的受支持值,或字体家族中另一个匹配程度更高的字体面;如果选定字体面缺少某个字符,则会针对该字符继续遍历回退字体家族列表。应声明准确的范围,从而避免浏览器选择无法生成所请求实例的字体面。
可变字体文件并不会自动小于所有静态字体集合。当页面需要使用足够大的已表示范围,以抵消额外的可变数据时,可变字体才更高效。
控制加载和布局偏移 #
font-display 定义回退行为:
block允许在回退前有一段很短的不可见文本时间。swap立即显示回退字体,并在字体面到达后进行替换。fallback使用较短的阻塞期和有限的替换期。optional允许浏览器在受限条件下继续使用回退字体。
swap 可以保持文本可读,但度量不匹配可能导致布局偏移。应选择比例相近的回退字体,或使用度量覆盖:
@font-face {
font-family: "Example Sans Fallback";
src: local("Arial");
size-adjust: 102%;
ascent-override: 92%;
descent-override: 24%;
line-gap-override: 0%;
}覆盖值应根据测量得到的字体度量推导,而不是凭猜测设置。
只预加载初始渲染期间所需的字体面:
<link
rel="preload"
href="/fonts/example-sans-latin.woff2"
as="font"
type="font/woff2"
crossorigin>预加载 URL、CORS 模式和 @font-face URL 必须匹配,否则浏览器可能下载两次资源。过度预加载会与关键 CSS、脚本和图像争夺资源。
按字符覆盖范围进行子集化 #
unicode-range 允许浏览器仅在文本需要相应代码点时下载字体面:
@font-face {
font-family: "Example Sans";
src: url("/fonts/example-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}所有子集合在一起必须覆盖组合标记、标点、符号以及所有受支持的语言。缺少组合标记可能产生无法与基础字符对齐的回退字形。
访问本地字体 #
在支持的浏览器中,window.queryLocalFonts() 可在获得用户许可后枚举本地安装的字体:
const fonts = await window.queryLocalFonts();
const matching = fonts.filter((font) => font.family === "Noto Sans");字体枚举会暴露可识别信息,因此受到严格的权限和可用性限制。不要让普通页面渲染依赖它;CSS 字体匹配已经会使用字体家族栈中指定的已安装字体。
@font-face 中的 local() 来源也会将已安装字体的可用性暴露给 CSS 匹配。出于隐私保护,浏览器可能忽略本地来源,或降低其精确度,因此应在本地提示之后提供可下载的来源:
@font-face {
font-family: "Example Sans";
src:
local("Example Sans"),
url("/fonts/example-sans.woff2") format("woff2");
}不要将长列表的本地字体探测用作指纹识别机制。
评论
在 GitHub 上阅读或评论(发表评论需要登录)