<p>vw 直接用于 calc()导致字号失准,因未限定响应区间;应使用线性插值公式 calc(14px + 6 * ((100vw – 320px) / 1600)),配合 Less mixin 封装、iOS 横屏 bug 规避及~”…” 转义防编译错误。</p>

calc()里用 vw 做字号为什么总不准
因为直接写 font-size: calc(16px + 0.5vw) 在小屏下可能比设计稿还大,大屏又增长过快——vw 是视口宽度的 1%,而字号通常只需要在某个区间内线性变化,不是无脑随屏幕拉伸。
真正要的是“在 320px 到 1920px 之间,字号从 14px 平滑过渡到 20px”,而不是让 1920px 设备显示 16px + 0.5 × 1920 = 112px 这种荒谬值。
- 先确定最小视口(如
320px)对应最小字号(如14px) - 再确定最大视口(如
1920px)对应最大字号(如20px) - 用线性插值公式:
calc(14px + (20 - 14) * ((100vw - 320px) / (1920 - 320))) - 注意分母必须是纯数字(不能带单位),所以
(1920 - 320)得手算成1600
Less 里怎么封装成可复用的 mixin
硬写一长串 calc() 既难读又难改,Less 的.fontsize-viewport() mixin 能把逻辑收拢,还能默认兜底。
关键点在于:Less 不能直接在 calc() 里做除法运算(浏览器解析时才计算),所以所有算术必须在 Less 编译期完成,只把最终系数传进去。
立即学习 “ 前端免费学习笔记(深入)”;
- 定义 mixin:
.fontsize-viewport(@min-vw: 320, @max-vw: 1920, @min-fs: 14px, @max-fs: 20px) {……} - 内部用
@ratio: (@max-fs - @min-fs) / (@max-vw - @min-vw);算出每 1px 视口宽度对应的字号增量(单位是px/vw) - 生成样式:
font-size: calc(@min-fs + @ratio * (100vw - @min-vw)); - 务必加
font-size: @min-fs;作为不支持calc()或vw的降级
移动端 iOS Safari 对 vw 的兼容性陷阱
iOS 9.3+ 支持vw,但有个经典 bug:横屏切换后,100vw 仍按竖屏宽度计算,导致字号突变。这不是 Less 或 calc 的问题,是浏览器渲染层没及时更新视口元信息。
真实影响场景:用户从竖屏点开一个弹窗,再横屏看——字体可能突然缩到极小,或撑破容器。
- 临时解法:监听
orientationchange事件,手动触发document.documentElement.style.fontSize = ''重绘 - 更稳做法:放弃纯
vw,改用clamp()(但 iOS 13.4+ 才支持) - 如果必须兼容 iOS 12,建议用
rem+ 媒体查询分段控制,vw仅作增强而非唯一方案
Less 编译后 calc 表达式被转义或报错
Less 默认会把 calc(100vw - 320px) 里的减号识别为 Less 运算符,导致编译失败或结果异常——比如输出成calc(100vw320px)。
根本原因是 Less 解析器优先尝试数学计算,而不是原样保留 CSS 函数。
- 用波浪号 + 引号包裹整个表达式:
font-size: ~"calc(100vw - 320px)"; - 或者把操作符前后加空格并用括号隔离:
font-size: calc(~"100vw" - ~"320px"); - 注意:~”…” 内部不能有变量插值,动态值必须拼进字符串,例如:
~"calc(@{min-fs} + (@{max-fs} - @{min-fs}) * ((100vw - @{min-vw}px) / @{range}))"
最易忽略的是:当用 @range 这种预计算变量时,它必须是纯数字(如 1600),不能带px 单位,否则字符串拼接后 calc() 语法非法。