第一次写 UniApp 项目的时候,我心里一直打鼓:设计稿上清清楚楚标着 750px,那我是不是应该写成 750rpx?换成逻辑分辨率只有 375px 的手机,这东西不会直接缩成一半吧。后面我又在论坛里看到有人说 rpx 就是 rem 的马甲,还有人言之凿凿说 rpx 是"小程序的 rem",搞得我更迷糊了。这问题其实特别典型,大部分刚接触跨端开发的人都会卡在这一步。今天这篇文章,我就把 rpx 的来龙去脉、换算逻辑、和 rem 的本质差异全部说清楚,顺便把我自己在实际项目里踩过的坑一并交代。
1. rpx 是什么:一套"设计稿宽度即代码数值"的跨端单位
1.1 我最初对 rpx 的误解
先说说大多数人的直觉。很多人第一次看到 rpx,第一反应是"这是不是 responsive pixel,响应式像素"。然后打开开发者工具,在 iPhone 逻辑宽度 375px 的模拟器上量一下,发现 750rpx 刚好铺满整个屏幕,于是得出一个粗浅结论:rpx 大概是"把屏幕宽度当成 750 来用的单位"。
这个理解前半段是对的,但后半段容易跑偏。更常见的误区是,有人把 rpx 当成一种"px 的自动乘除工具",觉得它的作用和 rem 一模一样,只是换个名字。等你真的在平板上跑一下,或者把系统字体调大,就会发现这俩根本不是一回事。rpx 的本质,是一套按屏幕宽度等比缩放的度量系统,而 rem 的本质,是围绕"根元素字号"做相对缩放,两者的触发机制和适用边界差异非常大。
1.2 rpx 的官方约定:屏幕宽度拆成 750 份
rpx 的规则可以用一句话讲完:无论设备屏幕有多宽,都把它当作 750 等份,每一份就是 1rpx。
举个例子,假设一台手机的逻辑分辨率是 375px,那屏幕宽度被分成 750 份之后,1rpx 就等于 0.5px。如果一台安卓机逻辑分辨率是 412px,1rpx 就等于 412 / 750 ≈ 0.549px。如果 iPad 的逻辑宽度是 768px,1rpx 就等于 768 / 750 ≈ 1.024px。
也就是说,rpx 不是一个固定长度,它是一个会根据屏幕宽度动态变化的"相对长度单位"。正因为这个特性,你在 750px 宽的设计稿里量到的尺寸,可以直接把数值抄到代码里:设计稿上按钮宽度是 200px,你写 200rpx,窄屏上会自动变小,宽屏上会自动变大,最终保证这个按钮在屏幕上占的"视觉比例"是一致的。
1.3 为什么偏偏是 750,而不是 375 或 100
这个 750 不是随便拍脑袋定的。早年移动端页面的主流设计稿宽度就是 750px,原因是那个时期的主流机型逻辑分辨率通常为 375px,而物理像素是它的 2 倍,也就是 750px。设计师为了在高清屏幕上出图,默认会按 2 倍尺寸设计,于是 750px 成了事实上的设计稿标准。
如果基准定成 375,那设计稿里的数值还得手动除以 2,显然不方便。定成 750 的聪明之处在于,它让"设计稿 px 数值"与"代码 rpx 数值"直接一一对应,设计师和前端之间的沟通成本瞬间降低。你可能还会问:为什么不学 vw,把屏幕宽度定成 100 份?那样的话,1rpx 相当于 0.1333vw,也能做等比缩放。但它存在一个现实问题:设计稿上 100px 的按钮,你要先换算成 100 / 750 = 0.1333,再乘以 100vw,写起来不如直接写 100rpx 来得直观。所以 750 这个数字,本质上是"设计习惯"与"换算成本"之间平衡出来的结果。
2. rpx 的缩放原理:和 vw 同源,但不是一回事
2.1 换算公式与手算实例
rpx 在代码层面最终会被编译成真实的 px。它的计算公式可以写成:
1rpx = 屏幕逻辑宽度(px)/ 750
反过来,如果你想知道某个元素在目标设备上到底占多少像素:
实际像素 = rpx 数值 × 屏幕逻辑宽度 / 750
举个实际例子。设计稿宽度 750px,里面有一个卡片,宽度标注 600px 高 300px。在逻辑宽度 375px 的手机上:
卡片实际宽 = 600 × 375 / 750 = 300px
卡片实际高 = 300 × 375 / 750 = 150px
正好占屏宽的五分之四左右,和设计稿比例一致。换到逻辑宽度 412px 的手机上:
卡片实际宽 = 600 × 412 / 750 = 329.6px
卡片实际高 = 300 × 412 / 750 = 164.8px
视觉占比依然接近五分之四。这就是 rpx 的核心价值:它保证的是"元素占屏幕宽度的比例",而不是一个绝对像素值。
2.2 它和 vw、vh 的关系
从数学角度讲,rpx 和 vw 几乎是同一种东西。1vw 等于屏幕宽度的 1%,也就是屏幕宽度除以 100;1rpx 等于屏幕宽度的 1/750。所以:
1rpx = 100vw / 750 = 0.1333vw
1vw = 750rpx / 100 = 7.5rpx
也就是说,如果你愿意,完全可以用 vw 替代 rpx,无非是多做一次换算。UniApp 在 H5 端和小程序端都支持 vw,理论上你写 vw 也能实现等比缩放。但 rpx 的优势在于它已经帮你把"设计稿 750 基准"这件事固化了,少一层心算。还有一个细节:vw 是严格按"视口宽度"来计算的,而 rpx 在部分端上会受容器或根环境的影响,不过绝大多数场景下,两者表现非常接近。
2.3 高度用 rpx 时的隐藏问题
rpx 的等比缩放只依赖屏幕宽度,不依赖屏幕高度。这意味着你用 rpx 设置元素高度时,这个高度也是按"屏幕宽度"的缩放系数来换算的,而不是按屏幕高度。
举例来说,设计稿里有个弹窗,高 900rpx,在 375px 宽、667px 高的竖屏手机上,它实际高 900 × 375 / 750 = 450px,占屏高约 67.5%。但在横屏状态下,假设逻辑宽度变成 667px,那同一个弹窗的高变成 900 × 667 / 750 = 800.4px,几乎充满整屏。问题就来了:同样的 rpx 值,横屏时高度暴涨,弹窗大概率溢出。
这不是 bug,而是 rpx 的定位造成的:它只管"宽度方向上的比例",高度方向只是被宽度牵连。所以如果你要做一个高度敏感的布局,比如"一屏内展示一个半屏的列表",或者横屏适配,强烈建议高度方向混用 vh、百分比或者计算属性,而不是所有尺寸无脑 rpx。
3. 和 rem 硬碰硬:差的不只是"基准值"
3.1 rem 到底怎么工作
rem 是 CSS 里非常经典的单位,全称 root em,意思是"相对根元素字号"。它的换算极其简单:如果根元素 html 的字号是 16px,那么 1rem 就等于 16px,2rem 等于 32px。默认情况下,根字号是浏览器自己设定的,通常是 16px。
很多人做移动端适配时,用 JS 根据屏幕宽度去修改根字号,例如把屏幕宽度 375px 的根字号设成 37.5px,然后把设计稿里的 100px 写成 100rem。注意这里有个容易混淆的点:在这种方案里,1rem 不是固定等于 1px,而是相当于是"设计稿像素的 1/10",因为 1rem = 37.5px = 屏幕宽度的 1/10。这是 rem 适配的本质:先定义一个"缩放基准",再把所有尺寸都表示成这个基准的倍数。
3.2 一张表看清 rpx 与 rem 的差异
我用一个表格总结一下,这样对比最直观:
| 对比维度 | rpx | rem |
|---|---|---|
| 基准长度 | 屏幕宽度的 1/750 | 根元素字号的 1 倍 |
| 是否随屏幕宽度自动缩放 | 是,框架内置 | 否,需要 JS 修改根字号才会缩放 |
| 默认行为 | 天然等比缩放 | 初始固定,相当于 px 的别名 |
| 依赖外部脚本 | 不依赖 | 通常依赖动态根字号脚本 |
| 对系统字体缩放的感知 | 不感知 | 感知(因为根字号可能被系统调节) |
| 典型适用场景 | 布局尺寸、间距、圆角 | 文本层级、可访问性、固定比例 |
| 在 UniApp 中的可用性 | 内置支持 | 支持,但需要自己管理缩放 |
看完这张表就能发现,rpx 和 rem 并不是"同一种思想的两版实现",而是两个维度的东西:一个是"按屏宽等比缩放",另一个是"按根字号等比缩放"。二者只有在"同时动态修改根字号"这个前提成立时,表面行为才会相似。
3.3 同一个页面在三种单位下的实际表现
假设设计稿宽 750px,里面有一个按钮,宽 200px、高 80px、文字 28px。现在把它分别用 px、rpx、rem 写出来,在屏幕宽度 375px 的设备上测试:
如果用 px,按钮宽 200px,视觉比例是 200 / 375 ≈ 53%。换到 412px 屏上,按钮还是 200px,视觉比例变成 48.5%。这就是固定像素的问题,它不随屏幕变化,看上去会"越来越小"。
如果用 rpx,按钮宽 200rpx,375px 屏上实际 100px,412px 屏上实际 109.87px,视觉比例稳定在 26.7% 左右。这是"等比缩放"的效果。
如果用 rem,并且你不改根字号,那 1rem = 16px,按钮 200rem 等于 3200px,直接爆屏。所以 rem 方案必须配合脚本,把根字号设为屏幕宽度的某个百分比,比如 375 屏根字号设 37.5px,按钮 200rem 依然爆屏。这说明 rem 的缩放系数完全由你决定,它不像 rpx 那样把"750 基准"固化进框架里。
3.4 rem 存在的"自主缩放"优势:系统字号适配
既然 rpx 这么方便,为什么还会有人坚持用 rem?最核心的原因是无障碍和系统字号适配。用户可以在系统设置里调大字体,如果网页的根元素字号发生变化,使用 rem 的文本会跟着变大,而使用 rpx 的文本不会,因为它只认屏宽,不认字号。
举个例子,一个资讯类 App,正文用 32rpx,在 375px 屏上等于 16px,阅读刚好。用户把系统大字模式打开后,32rpx 依然等于 16px,没有任何变化,对老花眼用户很不友好。但如果正文用 1rem,根字号从 16px 变成 24px 时,正文也跟着变成 24px,体验会好很多。所以我现在的习惯是:正文文本避免使用 rpx,要么 px,要么 rem,至少给系统字号适配留一条路。
4. UniApp 里用 rpx,真正的坑都藏在这些地方
4.1 设计稿不是 750:换算公式别记错
rpx 默认的隐含前提是"设计稿宽度 750px"。可现实中设计稿可能是 375px、1242px,甚至 1080px。如果设计稿宽度不是 750,所有标注都要按比例换算:
rpx 数值 = 设计稿标注值 × 750 / 设计稿宽度
比如设计稿宽 375px,标注宽度 200px,换算成 rpx 就是 200 × 750 / 375 = 400rpx。设计稿宽 1242px,标注宽度 621px,换算成 rpx 就是 621 × 750 / 1242 = 375rpx。绝大多数情况下,你先确认设计稿的宽度,再去做批量换算,顺手把团队的设计规范固定成"统一出 750 宽度"的稿子,能省掉大量重复劳动。
4.2 大屏和平板的"无限放大"问题
rpx 等比缩放看起来很美好,但有一个副作用:屏幕越宽,所有东西越大。在手机上,750 基准保证比例协调;换到平板,768px 逻辑宽度下,1rpx 约等于 1.024px,一个小按钮的宽高全都放大接近一倍,整个页面看起来像"老年模式"。
我做过一个跨端项目,产品要求在平板上实现"两栏布局"而不是手机上的"单栏全宽按钮",结果因为整个页面全部用 rpx,平板端按钮还是全宽、超大。后来解决方案很简单:在平板宽度断点内,不再用 rpx 做容器宽度,改用固定最大宽度或百分比布局,只有手机端才保留 rpx 的等比逻辑。如果你不想做这么复杂的适配,至少给根容器加一个 max-width,比如 500px,防止内容在平板上被无脑放大。
4.3 文本、边框、阴影不适合无脑 rpx
文本用 rpx 还有一个隐藏问题:字号的"可读性"并不完全跟屏宽成正比。在 375px 屏上,24rpx 等于 12px,能看清;在 412px 屏上,24rpx 等于 13.18px,差异不大;但在平板 768px 屏上,24rpx 等于 24.58px,标题像广告牌,正文也喧宾夺主。文本尺寸更适合跟随"用户偏好字号"和"阅读密度",而不是粗暴地跟着屏宽等比放大。
细边框也一样。你写 1rpx 边框,在 375px 屏上等于 0.5px,恰好能呈现"细线"效果;在 412px 屏上等于 0.55px,还行;但在某些屏幕上会出现渲染成 0 或虚化的情况。更稳妥的做法是从一开始就明确:需要小于 1px 的细线,用 px 直接写 1px,或者用 transform: scale(0.5) 模拟,而不是依赖 rpx 的浮点换算。阴影同理,box-shadow 的模糊半径用 rpx 很容易在不同端产生奇怪的模糊程度,建议大数值固定用 px 或 rem。
4.4 原生组件和动态样式的兼容盲区
UniApp 是一个跨端框架,会编译到 H5、小程序、App 等多个平台。不同的端对 rpx 的解析存在细微差异,尤其是在原生组件内部。比如原生地图、视频播放器、输入法的弹层,它们并不是普通 WebView 里的 DOM 元素,rpx 在它们内部可能不会按预期缩放,甚至完全不生效。
另外,动态绑定样式时也要小心。你在 JavaScript 里拼 style 字符串,给一个元素动态设置 width,如果拼的是200rpx,在大多数端没问题;但如果你需要根据运行时数据计算宽度,比如item.width * 0.72 + 'rpx',先在脑袋里过一遍:算出来的值是不是你想让它在屏幕上呈现的比例。rpx 的缩放是在渲染时发生的,所以运行时计算同样适用,但一定要保证计算基准一致,别一时顺手把设计稿 px 和运行时代码里的 px 混用。
4.5 rpx 遇上条件编译和组件隔离时的注意点
UniApp 支持条件编译,你可以针对不同平台写不同的样式。比如在小程序端用 rpx,在 App 端改用 px,实现上没问题,但要注意维护成本。我见过一个项目,条件编译里散落着三种单位,后来设计师改一个间距,前端要改五个文件,还经常漏掉某个平台。
组件隔离也是个值得注意的点。在 Vue 单文件组件里,style 加了 scoped 之后,rpx 的换算不受影响,这点不用担心。但如果你用了第三方 UI 库,它们的样式可能默认用 px 或 rem,和你的 rpx 混在一起后,视觉比例会突然不对。排查方式很简单:浏览器开发者工具里找到对应元素,看 Computed 样式里最终算出的 px 值,再对照你预期的比例,就能判断是哪个单位在捣乱。
5. 我的选型方法:把 rpx、rem、px 当作工具而非宿命
5.1 以"是否该随屏幕等比"来决策
我用 rpx 的标准很简单:这个属性需不需要"跟着屏宽等比缩放"。如果需要,比如按钮宽度、卡片间距、栅格留白,就用 rpx;如果不需要,比如文本字号、细边框、固定弹窗最大高度,就用 px 或 rem。这个判断标准比"统一全用 rpx"或者"彻底抛弃 rpx"靠谱得多。
以我自己做的一个偏内容型项目为例:
.card { width: 690rpx; /* 卡片宽度,跟随屏宽 */ padding: 24rpx 32rpx; /* 内边距,跟随屏宽 */ border-radius: 24rpx; /* 圆角,跟随屏宽 */ } .card__title { font-size: 32px; /* 正文标题,固定不随屏宽暴涨 */ line-height: 1.5; } .divider { height: 1px; /* 细线,用 px 保证渲染稳定 */ background: #e5e5e5; }这套规则的好处是,团队成员不用每次写样式都纠结半天,问一句"这个值跟随屏宽吗",答案就出来了。对应的,单位的使用也规整了。
5.2 用 CSS 变量做一套设计代币,避免单位散落各处
比单位更值得管理的是"设计数值本身"。我建议在项目里用 CSS 变量把设计规范沉淀成一套 token,而不是让开发者在代码里到处写24rpx、32rpx、40px。比如:
:root { --space-xs: 8rpx; --space-sm: 16rpx; --space-md: 24rpx; --space-lg: 40rpx; --radius-sm: 8rpx; --radius-md: 16rpx; --font-body: 28px; --font-title: 36px; }业务组件里只引用这些变量:
.card { padding: var(--space-md); border-radius: var(--radius-md); }这样做有几个直接好处:一是换单位时只改变量定义这一处,不用全局搜索替换;二是设计师改间距时,前端改一行,页面所有地方跟着变;三是新成员入职后,看到变量名就知道该用哪个值,不会凭感觉造一个"大概是 26rpx"的新尺寸出来。
5.3 一个简单的落地规范示例
我在团队里定的规范大概是这样的,你可以直接抄去改成适合自己项目的版本:
| 场景 | 推荐单位 | 原因 |
|---|---|---|
| 栅格、卡片、按钮等布局宽度 | rpx | 需要跟随屏宽等比缩放 |
| 间距、内边距、外边距 | rpx | 视觉节奏需要等比 |
| 圆角、阴影模糊、图标尺寸 | rpx 为主,阴影用 px | 阴影模糊在部分端渲染不稳定 |
| 正文、标题、说明文字 | px 或 rem | 保证可读性和系统字号适配 |
| 小于 1px 的细线边框 | px 配合 transform/hairline | 防止浮点渲染虚化 |
| 弹窗最大高度、整屏高度相关 | vh 或 calc | rpx 不感知屏幕高度,横向界场景会出问题 |
这份规范不是死规矩,它更多起到"防呆"作用。每次代码评审重点看两类问题:一是有没有把文本字号写成 rpx;二是有没有把弹窗高度写成 rpx。看过几轮之后,团队就形成条件反射了。
5.4 这套规范落地后踩到的一个实际反馈
有一次设计师给了一套新的视觉稿,按钮宽度从 200rpx 改成 180rpx,卡片间距从 24rpx 改成 16rpx。因为有设计代币,我只改了变量文件里几个值,全站样式自动更新。但紧接着 QA 在平板上提了个 bug:卡片文字在平板上显得略小。我一看,卡片标题用的是 32px,在手机上 32px 看起来和谐,平板上其实应该更大一些才对。
这个问题的根源恰恰是"我用了 px 保护文本,却丢掉了等比放大"。最后我调整了策略:标题这类相对重要的文本,改用clamp(24px, 4vw, 40px)这样的表达式,让它既不像 rpx 那样线性放大,也不会在平板上纹丝不动。这就是单位选型的取舍艺术——纯 rpx 解决不了所有问题,纯 px 也不行,关键是分清当前需求更看重哪一个维度。
6. 最后分享一点使用习惯
如果你问我个人最推荐的开局方式,我会说:新建项目时,默认布局单位全用 rpx,文本字号全用 px,然后跟着真实设备去调,而不是一开始就堆一套复杂的 JS 根字号适配脚本。先把基础跑通,等真的遇到平板适配、系统大字、横屏场景,再切换到对应的混合方案。我在实际项目里发现,绝大多数页面 80% 的单值用 rpx 就够了,剩下 20% 的边界情况,用 px、rem、vh 单独处理,代价远比全局改造小。
还有一个小技巧:在真机上调试时,多看开发者工具里 Computed 样式那一栏,它会把 rpx 换算后的实际 px 值告诉你。对比一下设计稿标注的比例,你就知道当前单位设置是否符合预期。毕竟设计稿是静态的,rpx 换算却是动态的,培养这种"用比例思考,而不是用标注思考"的习惯,才是跨端开发里真正值钱的经验。