必须用@mixin font-face封装声明、@function font-stack管理字体族、@use显式导入三者协同;否则模块化项目中易出现字体不生效、函数未定义、路径404等问题。

直接结论:用 @mixin font-face 封装声明 + @function font-stack 管理字体族 + @use 显式导入,三者缺一不可;否则在模块化项目(如 Vue/React + SCSS Modules)中会遇到字体名不生效、函数未定义、路径 404 等问题。
为什么 @font-face 必须封装成 mixin 而不是直接写死
硬写 @font-face 会导致重复声明、无法复用参数、难以按字重/样式批量生成。比如你要引入 Regular / Bold / Italic 三个变体,手写三遍容易漏掉 font-style: italic 或写错 src 路径。
- 必须用
@mixin font-face($name, $file, $weight: normal, $style: normal)统一控制font-display: swap、format()顺序、本地 fallback(local())等关键项 -
$file不拼接扩展名,由 mixin 内部补.woff2和.woff,避免调用时写错后缀 - 别在 mixin 里写
url('#{$font-path}#{$file}.woff2')这种拼接——路径变量应来自顶层@use的配置文件,而非 mixin 内部硬编码
font-family 名称加不加引号?大小写/空格怎么处理
只要字体名含空格、数字、连字符或大写字母,font-family 值就必须用英文双引号包裹,且声明与引用必须完全一致。浏览器不会自动标准化大小写或忽略空格。
- ❌ 错误:
font-family: Poller One;→ 浏览器解析为两个字体:Poller和One,回退到 sans-serif - ✅ 正确:
font-family: "Poller One", "Raleway", sans-serif;,且@font-face { font-family: "Poller One"; }中的字符串必须一字不差 - UniApp 项目特别注意:uni.scss 里只认变量和
@import,不支持@function,所以字体族函数必须放在单独文件(如fonts/_stack.scss),并在每个用到的地方@use显式引入
SCSS 模块中如何确保字体全局可用而不被 CSS Modules 隔离
@font-face 是全局注册行为,不受 CSS Modules 作用域限制,但前提是它得被实际编译进最终 CSS —— 这取决于你是否在正确位置 @use 或 @import 了声明文件。
- React .module.scss 中:必须
@use '@/styles/fonts/face.scss' as face;(不能只@import,否则 Sass 5+ 报 warning) - Vue 项目中:若用
sass-loader,确保@use路径以@/开头且 Webpack alias 已配好,否则报File to import not found - 禁止在
.module.scss里重复写@font-face—— 即使内容一样,也会被多次注入,触发浏览器字体重载,造成短暂闪动
字体路径 404 和格式兼容性最容易踩的坑
构建工具(Webpack/Vite)默认不处理 .ttf 或 .otf,只认 .woff2/.woff,且路径是相对于 @use 文件的位置,不是相对于 HTML 或 JS 入口。
- 路径错误典型现象:
Failed to load resource: the server responded with a status of 404 (),检查 DevTools Network 标签页里请求的 URL 是否多了一级src或少了一层fonts/ - 务必提供
woff2(首选)+woff(兜底),不要只放ttf;src列表里把local("Font Name")放最前,加速已有字体的复用 - 别信“自动转格式”插件:有些 Webpack loader 会把
.ttf转成 base64 内联,体积暴增,且无法利用浏览器字体缓存
真正麻烦的从来不是写几行 @font-face,而是字体名大小写不一致、路径相对基准搞错、模块系统下函数未加载、以及构建工具对字体后缀的静默忽略——这些点不逐个验证,上线后字体空白或回退就只能靠肉眼排查。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











