CSS @font-face

让图标字体在网页上运行的 CSS 规则——在样式表中声明、加载和使用自定义字体文件。

基础知识

@font-face 是 CSS 的 at 规则,用于告诉浏览器在哪里找到字体文件以及如何称呼它。早在 1997 年 IE 4 就已支持,但直到 2010 年前后,随着 WOFF 的出现和其他浏览器对该规则的一致实现,它才真正在跨浏览器中变得实用。

对于图标字体,@font-face 是字体文件与显示图标的 CSS 类之间的桥梁。没有它,浏览器就无从得知 font-family: 'MyIcons' 应该从服务器加载哪个具体文件。

基本语法
@font-face {
  font-family: 'MyIcons';
  src: url('fonts/myicons.woff2') format('woff2');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

font-family 描述符为字体命名,供后续引用。src 描述符告诉浏览器下载文件的位置及文件格式。font-weightfont-style 描述符确保浏览器不会尝试合成粗体或斜体变体。font-display 控制字体加载期间的显示行为。

现代字体栈

每个 URL 后的 format() 提示告诉浏览器文件的格式,以便它在不支持某格式时无需下载即可跳过。随着浏览器支持的改善,推荐的格式组合已大幅缩减。

现代写法(推荐)
@font-face {
  font-family: 'MyIcons';
  src: url('myicons.woff2') format('woff2');
  font-display: swap;
}

凭借 97%+ 的浏览器覆盖率,仅使用 WOFF2 对绝大多数现代项目已经足够。这是最简洁、性能最优的方式。

带 WOFF 兜底(支持 IE 11)
@font-face {
  font-family: 'MyIcons';
  src: url('myicons.woff2') format('woff2'),
       url('myicons.woff') format('woff');
  font-display: swap;
}

添加 WOFF 作为兜底可覆盖不支持 WOFF2 的 IE 11。现代浏览器会加载 WOFF2 文件;IE 11 则回退到 WOFF。

完整旧版栈(支持 IE 6-8)
@font-face {
  font-family: 'MyIcons';
  src: url('myicons.eot');                    /* IE9 兼容 */
  src: url('myicons.eot?#iefix') format('embedded-opentype'),
       url('myicons.woff2') format('woff2'),
       url('myicons.woff') format('woff'),
       url('myicons.ttf') format('truetype');
  font-display: swap;
}

完整的"防弹"栈包含:EOT(IE 6-8)、WOFF2(现代浏览器)、WOFF(IE 9-11)以及 TTF 作为最终兜底。浏览器按顺序尝试每条 src,使用第一个支持的格式。该方式仅在有极端旧版要求的项目中才有必要。

使用图标类

图标字体的标准模式是:用一个基础类设置 font-family 和共享渲染样式,再用各图标类通过 ::before 伪元素的 content 属性设置各图标对应的 Unicode 码位。

CSS 图标类
.icon {
  font-family: 'MyIcons';
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-home::before { content: '\E001'; }
.icon-search::before { content: '\E002'; }
.icon-user::before { content: '\E003'; }

基础类重置字体样式,防止浏览器应用会扭曲图标的粗体、斜体等变换。-webkit-font-smoothing-moz-osx-font-smoothing 属性在 macOS 和 iOS 上启用抗锯齿,使渲染更清晰。

每个图标类为 ::before 伪元素设置该字形对应的 Unicode 码位。反斜杠 E 记号(\E001)是 CSS 用十六进制码位引用 Unicode 字符的方式。

HTML 用法
<i class="icon icon-home"></i>
<span class="icon icon-search"></span>

<i><span> 效果相同。元素本身为空——图标完全由 ::before 伪元素渲染。

font-display

font-display 描述符控制在字体文件仍在下载时浏览器的显示行为。这对图标字体至关重要,因为错误的设置可能导致图标在页面加载期间不可见。

行为最适用于
swap立即显示回退文字,字体加载后切换为图标字体图标字体(推荐)
block短暂隐藏文字(最长 3 秒),然后显示回退不希望有闪烁的文字字体
fallback短暂阻塞(约 100ms)+ 短暂切换(约 3 秒)文字字体的平衡选项
optional浏览器可能在慢速连接时完全跳过该字体非必要的装饰性字体

对于图标字体,swap 是推荐选择。短暂的无样式内容闪烁(图标码位可能短暂显示为方块或空白)远好过图标完全不可见。使用 block 时,用户在慢速连接下可能会看到长达 3 秒的空白——页面看起来像是崩了。使用 swap,图标会在字体加载完成后立即出现,在现代网络连接下这个过渡几乎感知不到。

加载优化

字体文件默认会阻塞渲染——浏览器要等字体文件下载完成后才会用自定义字体渲染文字。以下是最小化影响的技巧:

  • 预加载字体文件——使用 <link rel="preload">,让浏览器尽早开始下载字体,甚至早于解析引用该字体的 CSS。
  • 自托管字体——从与 HTML 相同的源提供字体文件,可避免额外的 DNS 查询和连接建立,同时消除 CORS 问题。
  • 精简字体子集——删除未使用的图标以减小文件大小。一个有 500 个图标却只用了 50 个的字体,浪费了 90% 的下载。
  • 使用 unicode-range——如果有多个图标集,该描述符告诉浏览器只在页面实际使用了指定范围内的字符时才下载字体文件。
预加载字体文件
<link rel="preload" href="fonts/myicons.woff2" as="font"
      type="font/woff2" crossorigin>

即使是同源字体也需要添加 crossorigin 属性——这是字体加载规范的一个特殊要求。不添加它,浏览器会下载字体两次:一次来自预加载提示(不带 CORS),一次来自 @font-face 规则(带 CORS)。

常见问题

  • CORS 错误——从不同源(如 CDN 子域)提供的字体文件需要服务器设置 Access-Control-Allow-Origin 响应头。或者在 <link> 标签上使用 crossorigin 属性。如果没有正确的 CORS 配置,浏览器会静默拦截字体。
  • 图标显示为方块或矩形——通常意味着字体文件路径有误、字体尚未加载,或者图标类中的 font-family 名称与 @font-face 声明中的名称不匹配。检查浏览器的"网络"标签,确认字体文件以 200 状态码加载。
  • 图标显示为错误字形——与系统字体的 Unicode 码位冲突。如果图标字体使用的码位范围与常见系统字体重叠,浏览器可能会渲染系统字符。图标字体通常使用私有使用区(U+E000 至 U+F8FF)来避免此问题。
调试提示
打开浏览器开发者工具,进入"网络"标签,按"Font"筛选。你应该能看到 .woff2 文件以 200 状态码加载。如果找不到,说明路径有误。如果显示 CORS 错误,检查服务器响应头。如果文件已加载但图标仍不显示,检查元素并验证 font-family 是否完全匹配。
在 Bobcorn 中
Bobcorn 为你生成完整的 CSS 文件——包括 @font-face 声明、基础 .icon 类,以及包含正确 Unicode 码位的各图标类。CSS 使用你选择的字体名称,并用相对路径引用字体文件。在导出对话框中启用 CSS 选项,即可将其与字体文件一起包含在导出内容中。