rpx 单独使用无法适配所有设备,需结合条件判断与安全区域处理:因 rpx 仅按屏幕宽度等比缩放,不考虑物理尺寸差异、安全区域及像素密度,导致 iphone 5 与 ipad pro 显示异常、刘海屏遮挡、安卓高 dpr 模糊等问题。
直接用 rpx 就能覆盖绝大多数手机屏幕,但仅靠它不够——iphone 5 和 ipad pro 的物理宽度差近两倍,rpx 按比例缩放后,内容可能撑不满或挤成一团。真正有效的适配,是 rpx + 条件判断 + 安全区域处理的组合拳。
为什么 rpx 单独用会出问题
rpx 的换算逻辑是「1rpx = 屏幕宽度 / 750」,它只管横向等比缩放,不考虑设备实际能力:
- 在 iPhone 5(320px 宽)上,
750rpx渲染为 320px,刚好满屏;但在 iPad Pro(1024px 宽)上,750rpx只占约 75% 宽度,留白严重 - 刘海屏、挖孔屏、全面屏底部横条这些「安全区域」边界,
rpx完全不感知,容易把按钮盖在状态栏下或卡在虚拟导航键里 - 某些安卓机高 DPR(如 3.5)但
rpx换算后像素密度溢出,文字发虚、边框糊成一片
uni.getSystemInfo 获取真实设备参数
不能只依赖设计稿的 750px 基准,得看真机反馈。关键字段要立刻存进响应式数据里:
-
res.windowWidth:当前可渲染区域宽度(不含 status bar、软键盘),比screenWidth更可靠 -
res.pixelRatio:用于判断是否需要加载 2x/3x 图,也影响字体渲染清晰度 -
res.safeArea:iOS 11+ / Android 10+ 返回对象,含top、bottom、left、right四个偏移值 -
res.model和res.system:粗筛机型,比如/iPhone.*X|12|13|14|15/i匹配刘海屏,/iPad/i单独处理分栏逻辑
示例:在 onLoad 中获取并设置响应式 class
uni.getSystemInfo({
success: (res) => {
const isPad = res.windowWidth > 768;
const isNotch = res.safeArea && (res.safeArea.top > 20);
this.$nextTick(() => {
this.$el.classList.toggle('pad-layout', isPad);
this.$el.classList.toggle('notch-safe', isNotch);
});
}
});
用 @media 补齐 rpx 的盲区
CSS 媒体查询不是“备选方案”,而是对 rpx 的必要校准,尤其在 H5 端和小程序 PC 宽屏模式下:
- 别只写
@media (min-width: 768px),H5 在桌面浏览器缩放时window.innerWidth会变,优先用@media (min-width: 768px) and (hover: hover)区分触屏/非触屏 - 小程序里媒体查询支持有限,但 H5 端可放心用:
@media (max-height: 600px)处理小屏折叠手机,@media (orientation: landscape)锁定横屏布局 - 避免嵌套过深:媒体查询只控制容器级 class,内部元素继续用
rpx,保持层级清晰
常见错误:在 pages.json 里配了 "usingComponents",却忘了 H5 端的 media query 需要额外加 .h5 类名前缀才能生效
安全区域必须手动预留,不能靠组件自动适配
uni-app 的 uni-tabbar、uni-nav-bar 默认不读取 safeArea,顶部状态栏和底部横条区域必须自己算:
- 顶部:用
statusBarHeight+ 自定义导航栏高度(iOS 通常 44px,Android 48–64px 不等) - 底部:用
res.safeArea.bottom,注意微信小程序中该值在部分安卓机返回 0,需 fallback 到env = 'android' ? 48 : 34 - 最稳妥方式:在根容器加 padding,通过 computed 动态生成内联 style,而不是写死 CSS
例如在页面 <template></template> 顶层加:
<view :style="{ 'padding-top': statusBarHeight + 'px', 'padding-bottom': safeBottom + 'px' }">...</view>
真正麻烦的从来不是单位换算,而是不同设备对「安全」的定义不一致——有的把虚拟导航键算进安全区,有的不算;有的状态栏高度随横竖屏变化,有的固定。每次新增一个机型,都得重新测一遍 safeArea 是否准确,这个动作没法省。











