SCSS变量需按用途分层定义字体堆栈,因不同场景(标题/正文/代码)对字体特性要求不同,单变量无法兼顾语义、fallback顺序与平台兼容性;系统字体必须前置,否则iOS或旧Android会降级到难看默认字体。

直接说结论:用 SCSS 变量 + 字体堆栈分层定义,比硬写 font-family 值强十倍;但变量名必须带语义、堆栈顺序不能错、系统字体必须前置,否则在 iOS 或旧版 Android 上会 fallback 到难看的默认字体。
为什么不能只写一个 $font-sans 变量?
很多人图省事,定义一个 $font-sans: 'Inter', 'Segoe UI', sans-serif; 就完事。问题在于:
- 不同场景需要不同堆栈:标题要更稳重(比如加
'Georgia'),正文要更易读(比如优先'-apple-system'),代码块要等宽('SFMono-Regular') - SCSS 变量不支持运行时切换,但字体堆栈是“静态 fallback 链”,一旦写死就无法按设备/主题动态调整
- 直接拼字符串容易漏空格或引号,编译后变成
font-family: 'Inter''Segoe UI' sans-serif这种语法错误
推荐结构:按用途拆分变量 + 用 @function 组合堆栈
先定义原子级字体族变量,再用函数组装,兼顾复用性与可读性:
// styles/_fonts.scss
$font-system-sans: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
$font-system-serif: 'Georgia', 'Times New Roman', serif;
$font-mono: 'SFMono-Regular', 'Consolas', 'Liberation Mono', monospace;
@function font-stack($type: sans) {
@if $type == sans { @return $font-system-sans; }
@if $type == serif { @return $font-system-serif; }
@if $type == mono { @return $font-mono; }
@return $font-system-sans;
}
使用时直接调用:
立即学习“前端免费学习笔记(深入)”;
.title { font-family: font-stack(serif); }
.code { font-family: font-stack(mono); }
body { font-family: font-stack(sans); }
好处是:修改某类系统字体只需改一个变量;新增堆栈类型(如中文专用 $font-chinese)不影响现有逻辑;函数还能加参数做轻量定制(比如加 $weight: normal 控制是否插入 font-weight)。
UniApp 和 Vue 项目里特别要注意的坑
在 uni-app 中,如果你把字体变量放在 uni.scss 里,它会被自动注入——但 @function 不会被识别,必须用 @import 显式引入含函数的文件。而 vue 项目用 sass-loader 通常没问题,但要注意:
- 路径别写错:
@import '@/styles/fonts.scss';中的@/必须存在,否则 Webpack 找不到 - 不要在
style标签里重复@import多次,会导致变量被覆盖(SCSS 不是 JS,没有 hoisting) - iOS Safari 对引号敏感:写
'-apple-system'没问题,但写-apple-system(没引号)会直接忽略整条font-family - Android WebView 67 以下版本不支持
system-ui,必须显式列出-apple-system和BlinkMacSystemFont
字体堆栈顺序为什么不能乱?
浏览器按从左到右顺序尝试加载字体,一旦某个字体能被解析(哪怕只是名字匹配),就不会继续往后试。所以:
- 系统字体必须放最前:它们零延迟、零网络请求、渲染最稳
- Web 字体(如 Google Fonts)必须放中间,且确保已通过
@font-face正确声明,否则 fallback 会跳过它直奔最后的sans-serif - 通用族名(
sans-serif,serif,monospace)必须放最后,这是保底,不是占位符
错例:font-family: 'Inter', sans-serif, 'Segoe UI'; —— 浏览器看到 sans-serif 就停了,根本不会加载 'Segoe UI'。


















