8.4 自定义字体(@font-face)

学习目标

  • 掌握@font-face规则的语法结构及字体格式要求
  • 理解字体文件格式(TTF/OTF/WOFF)的兼容性差异
  • 学会优化自定义字体加载性能(字体子集、预加载策略)
  • 能够解决自定义字体在不同浏览器中的渲染问题

概念讲解

@font-face是CSS3引入的核心特性,允许网页加载并使用用户系统中未安装的自定义字体文件,彻底摆脱了对系统默认字体的依赖。这一特性极大地提升了网页设计的视觉表现力,使设计师能够精确还原品牌字体和创意排版。

核心价值

  • 品牌一致性:确保跨平台字体显示一致,避免因系统字体缺失导致的设计偏差
  • 创意自由度:支持艺术字体、图标字体等特殊排版需求
  • 性能优化:通过WOFF2等现代格式减少字体文件体积,提升加载速度

字体格式对比

格式 全称 压缩率 浏览器支持 适用场景
TTF TrueType Font 无压缩 所有浏览器 本地开发测试
OTF OpenType Font 无压缩 所有浏览器 印刷行业标准格式
WOFF Web Open Font Format 中等压缩 IE9+、所有现代浏览器 通用Web字体格式
WOFF2 Web Open Font Format 2.0 高压缩(比WOFF小30%) Chrome 36+、Firefox 39+、Edge 14+ 现代网页首选
EOT Embedded OpenType 中等压缩 IE专用 仅IE6-8兼容需求

⚠️ 注意:WOFF2是目前最优选择,兼具高压缩率和广泛兼容性,建议作为主要格式,同时提供WOFF作为降级方案。

语法参考

基础语法结构

@font-face {
  font-family: "自定义字体名称"; /* 必须,用于后续引用 */
  src: 
    url("font.woff2") format("woff2"),  /* 现代浏览器优先加载 */
    url("font.woff") format("woff"),    /* 降级方案 */
    url("font.ttf") format("truetype"); /* 兼容性兜底 */
  font-weight: normal; /* 可选,指定字体粗细(normal/bold/100-900) */
  font-style: normal;  /* 可选,指定字体样式(normal/italic/oblique) */
  font-display: swap;  /* 可选,控制字体加载策略 */
  unicode-range: U+0020-007E; /* 可选,指定字体覆盖的字符范围 */
}

/* 使用自定义字体 */
body {
  font-family: "自定义字体名称", sans-serif;
}

关键属性详解

  1. font-family 定义字体名称,后续通过font-family属性引用。建议使用有意义的名称,如"Brand-Regular""IconFont"

  2. src 指定字体文件URL及格式,支持多格式声明(按优先级排序)。format()函数必须正确指定格式类型,帮助浏览器快速识别。

  3. font-weight/font-style 可定义同一字体家族的不同字重和样式,实现字体的精细化控制:

    /* 粗体版本 */
    @font-face {
      font-family: "Brand";
      src: url("brand-bold.woff2") format("woff2");
      font-weight: bold; /* 700 */
      font-style: normal;
    }
    
    /* 斜体版本 */
    @font-face {
      font-family: "Brand";
      src: url("brand-italic.woff2") format("woff2");
      font-weight: normal; /* 400 */
      font-style: italic;
    }
    
  4. font-display 控制字体加载过程中的显示策略,解决" FOIT (Flash of Invisible Text) "问题:

    • swap:先显示备用字体,字体加载完成后替换(推荐)
    • fallback:短暂隐藏(100ms)后显示备用字体
    • auto:由浏览器决定(可能导致FOIT)
    • block:隐藏文本直到字体加载完成(不推荐)
    • optional:仅在字体预加载成功时使用自定义字体
  5. unicode-range 指定字体覆盖的字符范围,实现字体子集化加载:

    /* 仅包含ASCII字符 */
    unicode-range: U+0020-007E;
    
    /* 仅包含数字和标点 */
    unicode-range: U+0030-0039, U+0021-002F, U+003A-0040;
    

实战示例

基础实现:引入品牌字体

/* 定义自定义字体 */
@font-face {
  font-family: "Montserrat";
  src: 
    url("montserrat-regular.woff2") format("woff2"),
    url("montserrat-regular.woff") format("woff");
  font-weight: 400; /* 正常字重 */
  font-style: normal;
  font-display: swap;
}

/* 应用到页面 */
body {
  font-family: "Montserrat", "Helvetica Neue", sans-serif;
  font-size: 16px;
  line-height: 1.5;
}

h1, h2, h3 {
  font-family: "Montserrat", "Helvetica Neue", sans-serif;
  font-weight: 700; /* 对应粗体字重 */
}

高级应用:图标字体实现

/* 定义图标字体 */
@font-face {
  font-family: "IconFont";
  src: url("icons.woff2") format("woff2");
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* 创建图标类 */
.icon {
  font-family: "IconFont" !important;
  speak: never; /* 阻止屏幕阅读器朗读 */
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
}

/* 具体图标 */
.icon-home:before { content: "\e001"; }
.icon-user:before { content: "\e002"; }
.icon-settings:before { content: "\e003"; }
<!-- 使用图标 -->
<div class="icon icon-home"></div>
<div class="icon icon-user"></div>

性能优化:字体预加载

在HTML头部添加<link rel="preload">提前加载关键字体:

<head>
  <link rel="preload" href="montserrat-regular.woff2" as="font" type="font/woff2" crossorigin>
</head>

⚠️ 注意:必须添加crossorigin属性,否则预加载的字体无法被@font-face使用。

注意事项

  1. 兼容性处理
    • IE9-11不支持WOFF2,需提供WOFF格式降级
    • iOS Safari < 10不支持font-display,可使用JavaScript字体加载库(如FontFaceObserver)
    • 中文字体体积较大,建议使用字蛛等工具提取子集
  2. 性能优化策略
    • 始终优先使用WOFF2格式
    • 对多字重字体拆分文件,而非单个大文件
    • 使用unicode-range拆分常用字符与特殊字符
    • 结合preload预加载关键字体
    • 限制每页使用的自定义字体数量(建议≤3种)
  3. 法律风险提示
    • 确保自定义字体拥有Web嵌入授权(尤其是商业字体)
    • 免费字体推荐:Google Fonts、Font Squirrel、思源黑体等
  4. 渲染问题解决
    • 字体模糊:在Windows上添加-webkit-font-smoothing: antialiased
    • 行高异常:自定义字体可能导致行高变化,需重新校准
    • 闪烁问题:使用font-display: swap或字体加载库

自测题

  1. 以下哪种字体格式压缩率最高且兼容性最广? A. TTF B. WOFF C. WOFF2 D. EOT
  2. 如何解决自定义字体加载时的" FOIT "问题? A. 设置font-display: block B. 设置font-display: swap C. 使用unicode-range限制字符集 D. 增加字体文件体积
  3. 实现图标字体时,为什么需要设置speak: never? A. 提高渲染性能 B. 防止屏幕阅读器朗读无意义字符 C. 兼容旧浏览器 D. 减小文件体积
  4. 以下哪个属性可以控制自定义字体的加载优先级? A. src中的URL顺序 B. font-weight C. unicode-range D. font-family

答案:1.C 2.B 3.B 4.A

扩展阅读