根本原因是less编译时rem基准与运行时document.documentelement.style.fontsize不一致,导致1.6rem在不同设备上物理尺寸差异近两倍;必须用全局@base-font-size变量统一基准并显式设置html{font-size},配合unit()函数安全转换px为rem。

直接原因不是Less写错了,而是rem的计算基准在编译时和运行时不一致——Less里写的1.6rem永远按你硬编码的值算,而浏览器实际按document.documentElement.style.fontSize算。
为什么font-size: 1.6rem在真机上忽大忽小
Less编译阶段根本不知道运行时html的font-size是多少。你写1.6rem,它就原样输出,等于把换算逻辑锁死在某个假设值(比如16px)上。但真实环境里,iPhone SE可能设了37.5px,iPad Pro可能是68.2px,结果1.6rem在两边物理尺寸差近两倍。
- 开发时看着正常,是因为Chrome DevTools模拟的是桌面默认16px;真机调试必须看
getComputedStyle(document.documentElement).fontSize返回的真实值 - 改了设计稿宽度(比如从375px切到414px),所有
rem值都要重算,手动搜替换极易漏 - 用了
postcss-pxtorem又在Less里自己转rem,会导致字号翻倍——比如24px → 1.5rem再被插件转一次,变成1.5rem → 2.25rem
必须用@base-font-size变量统一基准
所有rem值不能硬写,得基于一个全局可配置的变量,且这个变量必须定义在入口variables.less顶部,避免被局部作用域覆盖。
- 移动端常用:
@base-font-size: 37.5px;(对应375px设计稿下1rem=10px,方便心算) - PC兼容场景:
@base-font-size: 16px;(保持与系统默认一致) - 关键一步:CSS里必须显式写出
html { font-size: @base-font-size; },否则浏览器用默认16px,Less里的计算全失效 - 别用
@base-font-size: 100vw / 375 * 10;这类表达式——Less不支持运行时视口计算,编译就报错
用unit()函数安全转px为rem
直接写@px / @base-font-size * 1rem会失败,因为Less除法保留单位:24px / 16px结果是1.5px,不是纯数字1.5,再乘1rem就报Operation on an invalid type。
- 正确封装:
.px2rem(@px) { font-size: unit(@px / @base-font-size, rem); } - 调用时支持两种写法:
.px2rem(24px)或.px2rem(24)(unit()能自动处理无单位数字) - 如果项目已用
postcss-pxtorem,就彻底删掉Less层的转换函数——二者叠加是常见翻车点 - 旧版Less(unit(),需退化为字符串拼接,但精度差、易出错,建议升级
JS动态注入font-size不能少
媒体查询只是辅助,@media (max-width: 40rem)这种写法在iOS Safari里可能完全不触发,因为MQ解析时html的font-size还没生效。
- 必须用JS在运行时设置:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 375 * 37.5 + 'px'; - 放在
DOMContentLoaded后执行,避免取不到clientWidth - iOS Safari下要校验
devicePixelRatio:if (window.devicePixelRatio > 1) { width = width / window.devicePixelRatio; } -
viewport必须写全:<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">,缺initial-scale=1会导致横屏时rem突变
最常被忽略的是:Less里定义的@base-font-size只是编译期fallback,真正起效的是JS注入的值。两者必须对齐,否则调试时看到的1rem = ?px永远和你预期的不一样。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











