SCSS中px2rem函数核心是防崩,需解决类型错配、单位残留、基准错位三类问题:统一用$px / 1px剥离单位,基准值(如100)须与JS运行时设置的document.documentElement.style.fontSize严格对齐,推荐用@mixin替代@function以支持多属性、条件输出和伪元素等真实场景。

SCSS里写px2rem函数,核心不是“怎么算”,而是“怎么不让它崩”——类型错配、单位残留、基准错位这三类问题占了90%以上的报错和渲染异常。
为什么px2rem(32)常报Operation on an invalid type
根本原因是传入值单位状态不确定:可能是32(纯数字)、32px(带单位)、甚至32em(错误单位)。SCSS加减乘除要求操作数单位兼容,而32 / 100 * 1rem中,32无单位,1rem有单位,乘法合法;但32px / 100会保留px单位,再乘1rem就变成0.32px*rem,非法。
实操建议:
- 统一用
$px / 1px剥离单位,比unitless()+ 分支更稳,也比旧版strip-unit()更可靠 - 函数开头强制标准化:
@if unitless($px) { $px: $px * 1px; } - 后续只走
($px / 1px) / $base * 1rem这一条路径,不碰$px / $base这种裸除
为什么除以100而不是16?基准值必须和JS运行时对齐
除以100不是“约定俗成”,而是为750px设计稿+document.documentElement.style.fontSize = (window.innerWidth / 750) * 100 + "px"这套方案服务的。你写font-size: px2rem(32)期望输出0.32rem,那JS就必须让1rem真等于100px——否则0.32rem在页面上就是0.32×16=5.12px,小得看不见。
常见错配场景:
- JS里按
clientWidth / 375 * 37.5设根字号(即1rem = 37.5px),但SCSS函数仍用/ 100,结果缩放比例差2.67倍 - 设计稿是640px,JS用
/ 6.4,SCSS却没同步改$base - 硬编码
html { font-size: 50px },直接覆盖JS逻辑
什么时候该用@mixin代替@function
函数只能返回单个值,塞进属性值里;而mixin能展开成完整声明块,更适合真实开发流。
典型卡点:
- 伪元素
::before { content: "x" }里不能调用函数,content不支持表达式 - 需要同时转
font-size、padding、border-radius时,函数要写三遍px2rem(),mixin一次注入 - 想根据条件控制是否输出某条样式(比如
@if $has-border),函数做不到,mixin可以 - 涉及
calc()的混合单位场景(如width: calc(100% - #{$gap})),函数无法安全插值,mixin可校验$gap单位后拼接
别忽略的硬性限制:SCSS无法处理运行时信息
px2rem()只是编译期静态换算,它不知道屏幕宽度、DPR、用户缩放、媒体查询断点——这些全靠JS或CSS媒体查询在运行时接管。
这意味着:
- 函数里写
@if $dpr > 2毫无意义,$dpr不是SCSS变量,是JS读window.devicePixelRatio得到的 -
@media (max-width: 750px)必须手动改成@media (max-width: 7.5rem),函数不会自动扫媒体查询 - 第三方UI库(如Vant)内部用px写的样式,不会被你的
px2rem函数影响,得单独覆盖 -
calc(100px - 20px)这类表达式,函数无法拆解,PostCSS插件也常漏掉,必须人工检查
最易被忽略的一点:所有单位转换都依赖根字号设置时机。JS脚本必须在CSS加载前执行,否则首屏渲染用的是浏览器默认16px,等JS跑完才重绘——闪动、错位、调试困难全由此来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











