Less中单位转换的正确姿势:别指望它能自动帮你搞定rem
先说一个核心结论:Less本身并不具备运行时的单位转换能力——它没有像JavaScript那样的动态计算机制。所谓的“强制转换”,拆解开来其实只有三步:用unit()剥离单位、通过变量控制基准值、再手动拼接目标单位。这三个步骤缺一不可,任何一个环节遗漏都会导致错误。
举个最简单的例子:32px / 16计算结果为2px,而不是2rem。如果直接把这个结果用于font-size,浏览器要么报错,要么直接忽略。这不是Less的缺陷,而是它的设计原则——除法默认保留左侧的单位,不会自作主张将px转换成rem。

为什么32px / 16px不能直接当rem使用
原因在于Less除法的单位处理规则。当左侧是32px、右侧是16px时,结果是无单位的纯数字2。但写成32px / 16,结果却变成2px——它不会自动变成2rem。更糟糕的是,如果写成font-size: 32px / 16px * 1rem,结果会变成2px * 1rem → 2pxrem,浏览器直接无法识别。
那正确的做法是什么?经验表明,分三步走最为稳妥:
- 先用
unit(32px / 16, '')剥离单位,得到纯数字2; - 再手动拼接目标单位
2 + rem; - 或者用
unit(32px, 'px') / 16更安全,先明确提取数值再做除法。
永远不要依赖隐式单位合并。Less并不保证2 * 1rem会合并成2rem——某些版本甚至会输出2remrem这种奇怪的产物。
.px2rem()函数必须区分输入类型
设计师给出的标注往往不太规范——可能是24、24px,甚至2.4em。如果你的函数不区分输入类型,比如直接用unit(24, 'px')处理纯数字24,得到的是24px,而不是想要的24。
正确的做法是添加类型判断:
- 用
isnumber(@val)判断是否为纯数字(如24); - 用
isdimension(@val)+unit(@val) = px判断是否为24px; - 遇到
2.4em这类非px单位,建议直接透传,不要强行转为rem; - 如果漏掉类型判断,把带px的值传进
unit(24px, ''),会报Operation on an invalid type的错误。
基准值@base-font-size必须全局定义且可覆盖
这个变量并不是用来设置HTML的font-size的——它只是Less编译时进行换算的标尺。它必须出现在所有调用.px2rem()的文件之前,而且不能在@media块里重定义。为什么?因为Less编译期不执行媒体查询,写了也没用。
几个实践要点:
- 推荐在
variables.less顶部写@base-font-size: 37.5px;(对应750px设计稿÷10); - 构建时可以用Webpack的
DefinePlugin注入不同值,生成H5和小程序两套CSS; - 千万不要写成
@base-font-size: 16px;然后指望JS动态修改——JS修改的是DOM,Less已经编译完成,两者是脱钩的; - 如果项目已经使用了
postcss-pxtorem,就不要在Less层再写.px2rem()了,否则px会被转换两次,结果完全错误。
最后一点容易被忽略,但这才是核心逻辑:Less里所有单位运算都发生在编译期,与屏幕宽度、DPR、横竖屏毫无关系。所谓“适配”,本质上是你把多套预设值(比如@base-font-size: 37.5px和@base-font-size: 100px)提前编译成不同的CSS文件,再由JS或构建流程决定加载哪一套。指望Less自己响应viewport变化,就像让Excel表格自动调用摄像头——它没有这个能力。
