Skip to content

RPX 单位系统

介绍

rpx(responsive pixel)是 UniApp 提供的响应式像素单位,可以根据屏幕宽度进行自适应。rpx 单位使得开发者无需针对不同设备编写多套样式,实现一套代码适配所有屏幕尺寸。在 RuoYi-Plus-UniApp 项目中,rpx 是移动端样式开发的核心单位,结合 SCSS 变量系统和 WD UI 组件库,构建了完整的响应式布局体系。

核心特性:

  • 自动适配 - 根据屏幕宽度自动计算实际像素值,无需手动适配
  • 设计稿还原 - 以 750px 设计稿为基准,1:1 还原设计稿标注
  • 跨平台统一 - 在 H5、小程序、App 各端表现一致
  • 简化开发 - 无需编写媒体查询和多套样式代码
  • 变量集成 - 与项目 SCSS 变量系统深度集成

架构设计

单位转换体系

┌─────────────────────────────────────────────────────────────────┐
│                      RPX 单位转换体系                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐       │
│  │  设计稿标注   │───▶│   rpx 值     │───▶│   实际像素   │       │
│  │   750px      │    │   750rpx     │    │   动态计算   │       │
│  └──────────────┘    └──────────────┘    └──────────────┘       │
│                              │                                   │
│                              ▼                                   │
│  ┌──────────────────────────────────────────────────────┐       │
│  │               平台编译转换                             │       │
│  ├──────────────────────────────────────────────────────┤       │
│  │  H5:      rpx → rem/vw (postcss 转换)                │       │
│  │  小程序:  rpx → 原生 rpx (直接支持)                   │       │
│  │  App:     rpx → px (运行时计算)                       │       │
│  └──────────────────────────────────────────────────────┘       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

响应式布局层次

┌─────────────────────────────────────────────────────────────────┐
│                      响应式布局层次                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Layer 1: 屏幕尺寸                                               │
│  ┌─────────────────────────────────────────────────────┐        │
│  │  320px ~ 428px (手机) | 768px+ (平板) | 1024px+ (PC) │        │
│  └─────────────────────────────────────────────────────┘        │
│                              │                                   │
│                              ▼                                   │
│  Layer 2: rpx 换算                                               │
│  ┌─────────────────────────────────────────────────────┐        │
│  │  实际px = rpx值 × (屏幕宽度 / 750)                    │        │
│  └─────────────────────────────────────────────────────┘        │
│                              │                                   │
│                              ▼                                   │
│  Layer 3: 组件尺寸                                               │
│  ┌─────────────────────────────────────────────────────┐        │
│  │  按钮、输入框、卡片等 UI 组件自适应渲染               │        │
│  └─────────────────────────────────────────────────────┘        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

换算规则

基准说明

rpx 以 750px 宽度的设计稿为基准:

  • 设计稿宽度:750px
  • 屏幕宽度:750rpx
  • 换算公式:实际px = rpx值 × (屏幕宽度 / 750)

常见设备换算

设备屏幕宽度物理像素DPR1rpx 对应 px
iPhone SE (1st)320px640px20.427px
iPhone 6/7/8375px750px20.500px
iPhone 6/7/8 Plus414px1242px30.552px
iPhone X/XS/11 Pro375px1125px30.500px
iPhone XR/11414px828px20.552px
iPhone 12/13/14390px1170px30.520px
iPhone 12/13/14 Pro393px1179px30.524px
iPhone 12/13/14 Pro Max428px1284px30.571px
iPhone 15/16393px1179px30.524px
iPhone 15/16 Pro Max430px1290px30.573px
Android 常见360px1080px30.480px
Android 常见375px1125px30.500px
Android 常见412px1236px30.549px
小程序开发工具375px750px20.500px

换算公式表

设计稿标注rpx 值iPhone 6 (375px)iPhone 12 (390px)iPhone Pro Max (428px)
10px10rpx5px5.2px5.7px
20px20rpx10px10.4px11.4px
32px32rpx16px16.6px18.3px
48px48rpx24px24.9px27.4px
64px64rpx32px33.3px36.6px
100px100rpx50px52px57px
200px200rpx100px104px114px
375px375rpx187.5px195px214px
750px750rpx375px390px428px

换算示例

在 750px 设计稿中:

  • 设计稿标注 100px → 使用 100rpx
  • 设计稿标注 32px → 使用 32rpx
  • 设计稿标注 750px(全宽) → 使用 750rpx 或 100%

基本用法

尺寸设置

scss
.container {
  width: 750rpx;        // 全屏宽度
  padding: 32rpx;       // 内边距
  margin: 24rpx 0;      // 外边距
}

.card {
  width: 690rpx;        // 卡片宽度(750-30*2)
  height: 200rpx;       // 卡片高度
  border-radius: 16rpx; // 圆角
}

字体大小

scss
// WD UI 组件库字号变量
$-fs-big: 48rpx;           // 大型标题
$-fs-important: 38rpx;     // 重要数据
$-fs-title: 32rpx;         // 标题字号
$-fs-content: 28rpx;       // 正文字号
$-fs-secondary: 24rpx;     // 次要信息
$-fs-aid: 20rpx;           // 辅助文字

// 使用示例
.title {
  font-size: 32rpx;        // 标题字号
  line-height: 48rpx;      // 行高(1.5倍)
}

.content {
  font-size: 28rpx;        // 正文字号
  line-height: 40rpx;
}

.caption {
  font-size: 24rpx;        // 辅助文字
  line-height: 36rpx;
}

.small {
  font-size: 20rpx;        // 小号文字
  line-height: 28rpx;
}

间距系统

scss
// 项目间距变量
$spacing-xs: 8rpx;      // 超小间距
$spacing-sm: 16rpx;     // 小间距
$spacing-md: 24rpx;     // 中等间距
$spacing-lg: 32rpx;     // 大间距
$spacing-xl: 48rpx;     // 超大间距

// WD UI 边距变量
$-size-side-padding: 30rpx;        // 屏幕两边留白
$-size-side-padding-small: 12rpx;  // 屏幕两边留白小值

// 使用示例
.list-item {
  padding: $spacing-md $spacing-lg;
  margin-bottom: $spacing-sm;
}

.page {
  padding: $-size-side-padding;
}

与其他单位配合

rpx + px 混用

某些场景需要固定像素值,不随屏幕缩放:

scss
.border-box {
  // 边框使用 px,保持 1 像素清晰
  border: 1px solid #eee;

  // 内边距使用 rpx,自适应屏幕
  padding: 24rpx;
}

.icon {
  // 小图标使用 px,避免模糊
  width: 16px;
  height: 16px;
}

.fine-line {
  // 细线使用 px
  height: 1px;
  background: #eee;
}

rpx + % 混用

scss
.flex-container {
  display: flex;
  padding: 24rpx;
}

.flex-item {
  // 百分比实现等分
  width: 50%;
  // rpx 实现固定间距
  padding: 16rpx;
}

.grid-layout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24rpx;  // rpx 间距
}

rpx + vw/vh 混用

scss
.full-screen {
  width: 100vw;
  height: 100vh;
  padding: 32rpx;
}

.header {
  height: 88rpx;
  // 安全区域适配
  padding-top: env(safe-area-inset-top);
}

.footer {
  height: 100rpx;
  padding-bottom: env(safe-area-inset-bottom);
}

rpx + calc() 混用

scss
.sidebar-layout {
  display: flex;
}

.sidebar {
  width: 200rpx;
  flex-shrink: 0;
}

.main-content {
  // 减去侧边栏宽度
  width: calc(100% - 200rpx);
}

.card-with-margin {
  // 全宽减去两边边距
  width: calc(750rpx - 60rpx);
  margin: 0 30rpx;
}

常用尺寸规范

页面布局

scss
// 页面边距
$page-padding: 30rpx;

// 安全区域
$safe-area-top: env(safe-area-inset-top);
$safe-area-bottom: env(safe-area-inset-bottom);

// 导航栏高度
$navbar-height: 88rpx;
$navbar-height-with-status: calc(88rpx + env(safe-area-inset-top));

// 标签栏高度
$tabbar-height: 100rpx;
$tabbar-height-with-safe: calc(100rpx + env(safe-area-inset-bottom));

// 内容区域高度
$content-height: calc(100vh - $navbar-height - $tabbar-height);

组件尺寸

scss
// 按钮高度
$button-height-small: 48rpx;    // 小型按钮
$button-height-medium: 72rpx;   // 中型按钮
$button-height-large: 88rpx;    // 大型按钮

// 按钮内边距
$button-padding-small: 0 24rpx;
$button-padding-medium: 0 32rpx;
$button-padding-large: 0 72rpx;

// 输入框高度
$input-height: 88rpx;
$input-height-small: 64rpx;

// 单元格高度
$cell-height: 96rpx;
$cell-height-large: 112rpx;

// 头像尺寸
$avatar-size-small: 48rpx;
$avatar-size-medium: 64rpx;
$avatar-size-large: 96rpx;
$avatar-size-xlarge: 128rpx;

// 列表项高度
$list-item-height: 96rpx;
$list-item-height-compact: 80rpx;

圆角规范

scss
$radius-xs: 4rpx;       // 超小圆角 - 标签、徽章
$radius-sm: 8rpx;       // 小圆角 - 小型按钮
$radius-md: 12rpx;      // 中等圆角 - 卡片
$radius-lg: 16rpx;      // 大圆角 - 大型按钮、弹窗
$radius-xl: 24rpx;      // 超大圆角 - 底部弹出层
$radius-xxl: 32rpx;     // 特大圆角 - 特殊场景
$radius-round: 999rpx;  // 圆角胶囊
$radius-circle: 50%;    // 正圆

图标尺寸

scss
$icon-size-xs: 24rpx;   // 超小图标 - 标签内
$icon-size-sm: 32rpx;   // 小图标 - 列表右箭头
$icon-size-md: 40rpx;   // 中等图标 - 输入框图标
$icon-size-lg: 48rpx;   // 大图标 - 按钮图标
$icon-size-xl: 64rpx;   // 超大图标 - 空状态
$icon-size-xxl: 96rpx;  // 特大图标 - 结果页

阴影规范

scss
// 浅阴影 - 卡片悬浮
$shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);

// 中等阴影 - 弹出层
$shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);

// 深阴影 - 模态框
$shadow-lg: 0 8rpx 32rpx rgba(0, 0, 0, 0.16);

// 按钮阴影
$button-shadow-medium: 0 4rpx 8rpx 0;
$button-shadow-large: 0 8rpx 16rpx 0;

设计稿适配

750px 设计稿

这是 UniApp 默认支持的设计稿宽度,直接使用标注值:

scss
// 设计稿标注: width: 200px, height: 100px
.box {
  width: 200rpx;
  height: 100rpx;
}

375px 设计稿

如果设计稿是 375px,需要进行换算:

scss
// 375px 设计稿换算公式
// rpx值 = 设计稿标注px × 2

// 设计稿(375px)标注: width: 100px
.box {
  width: 200rpx; // 100 × 2 = 200
}

// 也可以使用 SCSS 函数自动转换
@function px375($px) {
  @return $px * 2rpx;
}

.box {
  width: px375(100);  // 输出 200rpx
  height: px375(50);  // 输出 100rpx
}

640px 设计稿

scss
// 640px 设计稿换算公式
// rpx值 = 设计稿标注px × 1.171875

@function px640($px) {
  @return $px * 1.171875rpx;
}

// 或者更精确的计算
@function px640($px) {
  @return $px * (750 / 640) * 1rpx;
}

配置设计稿宽度

pages.json 中可以配置 rpx 计算规则:

json
{
  "globalStyle": {
    "rpxCalcMaxDeviceWidth": 960,
    "rpxCalcBaseDeviceWidth": 375,
    "rpxCalcIncludeWidth": 750
  }
}

配置说明:

配置项说明默认值
rpxCalcMaxDeviceWidthrpx 计算使用的最大设备宽度960
rpxCalcBaseDeviceWidthrpx 计算使用的基准设备宽度375
rpxCalcIncludeWidth设计稿宽度750

响应式布局

Flex 布局 + rpx

scss
.card-list {
  display: flex;
  flex-wrap: wrap;
  padding: 24rpx;
  gap: 24rpx;
}

.card-item {
  width: calc(50% - 12rpx);
  padding: 24rpx;
  border-radius: 16rpx;
  background: #fff;
}

// 三列布局
.grid-three {
  display: flex;
  flex-wrap: wrap;
  gap: 20rpx;
  padding: 0 30rpx;

  .item {
    width: calc((100% - 40rpx) / 3);
  }
}

// 四列布局
.grid-four {
  display: flex;
  flex-wrap: wrap;
  gap: 16rpx;
  padding: 0 24rpx;

  .item {
    width: calc((100% - 48rpx) / 4);
  }
}

Grid 布局 + rpx

scss
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24rpx;
  padding: 24rpx;
}

.grid-item {
  height: 200rpx;
  border-radius: 12rpx;
}

// 自适应列数
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200rpx, 1fr));
  gap: 20rpx;
}

// 固定首列宽度
.fixed-first-grid {
  display: grid;
  grid-template-columns: 200rpx 1fr;
  gap: 24rpx;
}

自适应宽度

scss
.adaptive-box {
  // 最小宽度
  min-width: 200rpx;

  // 最大宽度
  max-width: 600rpx;

  // 自适应宽度
  width: 100%;
}

// 响应式容器
.responsive-container {
  width: 100%;
  max-width: 750rpx;
  margin: 0 auto;
  padding: 0 30rpx;
  box-sizing: border-box;
}

平台差异

H5 端

rpx 会被 postcss 转换为 rem 或 vw 单位:

scss
// 源码
.box {
  width: 200rpx;
  font-size: 28rpx;
}

// 编译后 (rem 方案)
.box {
  width: 5.33333rem;
  font-size: 0.74667rem;
}

// 编译后 (vw 方案)
.box {
  width: 26.66667vw;
  font-size: 3.73333vw;
}

H5 配置 (vite.config.ts):

typescript
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'

export default defineConfig({
  plugins: [uni()],
  css: {
    postcss: {
      plugins: [
        // rpx 转换配置
        require('postcss-rpx-transform')({
          viewportWidth: 750,
        }),
      ],
    },
  },
})

小程序端

rpx 是小程序原生支持的单位,无需转换:

scss
// 源码和编译后相同
.box {
  width: 200rpx;
  font-size: 28rpx;
}

小程序 rpx 特性:

  • 微信小程序完全支持 rpx
  • 支付宝小程序支持 rpx
  • 百度/字节小程序支持 rpx
  • QQ 小程序支持 rpx

App 端

App 端会根据屏幕宽度动态计算 rpx 对应的像素值:

scss
// 源码
.box {
  width: 200rpx;
}

// 运行时计算(假设屏幕宽度 375px)
// 实际渲染: width: 100px

App 端注意事项:

  • nvue 页面中 rpx 表现可能略有差异
  • 建议在 nvue 中使用 px 或 upx
  • App 端 rpx 计算更精确

工具函数

rpx 转 px

typescript
/**
 * rpx 转 px
 * @param rpx rpx 值
 * @returns px 值
 */
export function rpx2px(rpx: number): number {
  const systemInfo = uni.getSystemInfoSync()
  return rpx * (systemInfo.windowWidth / 750)
}

// 使用示例
const pxValue = rpx2px(100) // 在 375px 宽屏幕上返回 50

// 四舍五入版本
export function rpx2pxRound(rpx: number): number {
  const systemInfo = uni.getSystemInfoSync()
  return Math.round(rpx * (systemInfo.windowWidth / 750))
}

px 转 rpx

typescript
/**
 * px 转 rpx
 * @param px px 值
 * @returns rpx 值
 */
export function px2rpx(px: number): number {
  const systemInfo = uni.getSystemInfoSync()
  return px * (750 / systemInfo.windowWidth)
}

// 使用示例
const rpxValue = px2rpx(50) // 在 375px 宽屏幕上返回 100

// 四舍五入版本
export function px2rpxRound(px: number): number {
  const systemInfo = uni.getSystemInfoSync()
  return Math.round(px * (750 / systemInfo.windowWidth))
}

动态设置样式

typescript
/**
 * 获取 rpx 对应的实际像素字符串
 * @param rpx rpx 值
 * @returns 带 px 单位的字符串
 */
export function getRpxStyle(rpx: number): string {
  return `${rpx2px(rpx)}px`
}

// 使用示例
const style = {
  width: getRpxStyle(200),
  height: getRpxStyle(100),
}

批量转换

typescript
/**
 * 批量转换 rpx 值
 * @param values rpx 值对象
 * @returns px 值对象
 */
export function batchRpx2px<T extends Record<string, number>>(
  values: T
): Record<keyof T, number> {
  const result = {} as Record<keyof T, number>
  for (const key in values) {
    result[key] = rpx2px(values[key])
  }
  return result
}

// 使用示例
const sizes = batchRpx2px({
  width: 200,
  height: 100,
  padding: 24,
})

缓存优化版本

typescript
// 缓存系统信息,避免频繁调用
let cachedWindowWidth: number | null = null

function getWindowWidth(): number {
  if (cachedWindowWidth === null) {
    cachedWindowWidth = uni.getSystemInfoSync().windowWidth
  }
  return cachedWindowWidth
}

// 监听屏幕旋转,更新缓存
uni.onWindowResize(() => {
  cachedWindowWidth = uni.getSystemInfoSync().windowWidth
})

export function rpx2pxCached(rpx: number): number {
  return rpx * (getWindowWidth() / 750)
}

最佳实践

1. 统一使用 rpx

scss
// ✅ 推荐:统一使用 rpx
.component {
  width: 200rpx;
  height: 100rpx;
  padding: 24rpx;
  font-size: 28rpx;
  border-radius: 12rpx;
}

// ❌ 不推荐:混用多种单位
.component {
  width: 100px;
  height: 50px;
  padding: 12px;
  font-size: 14px;
}

2. 边框使用 px

scss
// ✅ 推荐:边框使用 px 保持清晰
.card {
  border: 1px solid #eee;
  padding: 24rpx;
}

// ❌ 不推荐:边框使用 rpx 可能模糊
.card {
  border: 2rpx solid #eee;
}

// ✅ 推荐:使用 0.5px 边框技巧
.fine-border {
  position: relative;

  &::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background: #eee;
    transform: scaleY(0.5);
  }
}

3. 定义变量复用

scss
// 定义尺寸变量
$page-padding: 30rpx;
$card-radius: 16rpx;
$font-size-base: 28rpx;
$spacing-md: 24rpx;

// 复用变量
.page {
  padding: $page-padding;
}

.card {
  margin: 0 $page-padding;
  border-radius: $card-radius;
  font-size: $font-size-base;
}

.list-item {
  padding: $spacing-md $page-padding;
}

4. 避免过小的 rpx 值

scss
// ✅ 推荐:使用 px 表示细线
.divider {
  height: 1px;
  background: #eee;
}

// ❌ 不推荐:过小的 rpx 值显示不稳定
.divider {
  height: 1rpx;
}

// ✅ 推荐:最小使用 2rpx
.thin-line {
  height: 2rpx;
  background: #eee;
}

5. 使用 SCSS 变量系统

scss
// 引用 WD UI 变量
@import '@/wd/components/common/abstracts/variable.scss';

.my-component {
  // 使用组件库变量
  font-size: $-fs-content;
  color: $-color-content;
  padding: $-size-side-padding;

  // 使用主题色
  background: $-color-theme;
  border-radius: $-button-medium-radius;
}

6. 响应式断点处理

scss
// 定义断点
$breakpoint-sm: 640px;
$breakpoint-md: 768px;
$breakpoint-lg: 1024px;

// 响应式混合宏
@mixin respond-to($breakpoint) {
  @media screen and (min-width: $breakpoint) {
    @content;
  }
}

.container {
  width: 750rpx;
  padding: 30rpx;

  @include respond-to($breakpoint-md) {
    max-width: 750px;
    margin: 0 auto;
  }
}

7. 安全区域适配

scss
// 底部按钮安全区域
.bottom-button {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 24rpx 30rpx;
  padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
  background: #fff;
}

// 顶部导航安全区域
.custom-navbar {
  height: 88rpx;
  padding-top: env(safe-area-inset-top);
  box-sizing: content-box;
}

8. 动画尺寸处理

scss
// 动画中使用 rpx 需注意性能
.animate-box {
  width: 200rpx;
  height: 200rpx;
  transition: transform 0.3s ease;

  // ✅ 推荐:使用 transform 进行动画
  &:active {
    transform: scale(0.95);
  }

  // ❌ 不推荐:直接修改 rpx 尺寸
  // &:active {
  //   width: 190rpx;
  //   height: 190rpx;
  // }
}

常见问题

1. 1rpx 边框显示问题

在某些设备上 1rpx 边框可能不显示或显示模糊。

问题原因:

  • 1rpx 在某些设备上计算后小于 1 物理像素
  • DPR 为 2 或 3 的设备显示效果不一致

解决方案:

scss
// 方案一:使用 transform 缩放
.border-bottom {
  position: relative;

  &::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background: #eee;
    transform: scaleY(0.5);
  }
}

// 方案二:使用固定 px
.border-box {
  border: 1px solid #eee;
}

// 方案三:使用 box-shadow
.border-shadow {
  box-shadow: 0 1px 0 0 #eee;
}

2. 字体大小限制

某些浏览器有最小字体限制(如 Chrome 最小 12px)。

问题原因:

  • H5 端浏览器限制最小字体
  • 20rpx 在某些设备上可能小于 12px

解决方案:

scss
// 方案一:使用 transform 缩放
.small-text {
  font-size: 24rpx;
  transform: scale(0.8);
  transform-origin: left center;
}

// 方案二:设置最小字体
.text {
  font-size: max(20rpx, 10px);
}

// 方案三:使用 -webkit-text-size-adjust
.small-text-container {
  -webkit-text-size-adjust: none;
}

3. rpx 在 nvue 中的使用

nvue 页面中 rpx 的表现可能与 vue 页面略有差异。

问题原因:

  • nvue 使用原生渲染引擎
  • rpx 计算方式与 webview 不同

解决方案:

scss
// nvue 中使用 px 单位
// 750px 设计稿下,1px = 1rpx / 2
.nvue-box {
  width: 100px; // 相当于 vue 中的 200rpx
}

// 或使用 upx (仅 nvue)
.nvue-box {
  width: 200upx;
}

4. 动态计算 rpx

需要在 JS 中动态计算尺寸时:

typescript
// 获取屏幕信息
const { windowWidth } = uni.getSystemInfoSync()

// 计算实际像素
const actualPx = (100 / 750) * windowWidth

// 设置样式
element.style.width = actualPx + 'px'

// 或使用工具函数
import { rpx2px } from '@/utils/rpx'
element.style.width = rpx2px(100) + 'px'

5. CSS 变量与 rpx

scss
// ❌ CSS 变量中不能直接使用 rpx 计算
:root {
  --button-height: 88rpx;
  --button-padding: 24rpx;
}

// ✅ 直接赋值可以
.button {
  height: var(--button-height);
  padding: var(--button-padding);
}

// ✅ calc 中使用 CSS 变量
.content {
  height: calc(100vh - var(--button-height));
}

6. 图片尺寸适配

scss
// 固定宽高比的图片
.image-container {
  width: 200rpx;
  height: 200rpx;

  image {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

// 宽度自适应的图片
.responsive-image {
  width: 100%;
  height: auto;
}

// 使用 padding-top 技巧保持比例
.aspect-ratio-box {
  position: relative;
  width: 100%;
  padding-top: 56.25%; // 16:9 比例

  image {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

7. 滚动容器高度计算

scss
// 固定头部和底部的滚动区域
.scroll-container {
  height: calc(100vh - 88rpx - 100rpx); // 减去导航栏和标签栏
  overflow-y: auto;
}

// 带安全区域的滚动容器
.scroll-with-safe {
  height: calc(
    100vh - 88rpx - 100rpx -
    env(safe-area-inset-top) -
    env(safe-area-inset-bottom)
  );
}

// 使用 scroll-view 组件
// template
// <scroll-view :style="{ height: scrollHeight + 'px' }" scroll-y>
// script
const systemInfo = uni.getSystemInfoSync()
const scrollHeight = systemInfo.windowHeight - rpx2px(188)

8. 弹窗位置计算

typescript
// 计算弹窗居中位置
function calculatePopupPosition(
  popupWidth: number,
  popupHeight: number
): { left: string; top: string } {
  const { windowWidth, windowHeight } = uni.getSystemInfoSync()

  const actualWidth = rpx2px(popupWidth)
  const actualHeight = rpx2px(popupHeight)

  const left = (windowWidth - actualWidth) / 2
  const top = (windowHeight - actualHeight) / 2

  return {
    left: `${left}px`,
    top: `${top}px`,
  }
}

9. Canvas 绑定 rpx

typescript
// Canvas 需要使用实际像素
const canvasWidth = rpx2px(600)
const canvasHeight = rpx2px(400)

// 绘制时使用转换后的像素值
ctx.fillRect(0, 0, canvasWidth, canvasHeight)

// 文字大小也需要转换
ctx.font = `${rpx2px(28)}px sans-serif`

10. 横屏适配

typescript
// 监听屏幕旋转
uni.onWindowResize((res) => {
  const { windowWidth, windowHeight } = res.size

  // 判断横竖屏
  const isLandscape = windowWidth > windowHeight

  if (isLandscape) {
    // 横屏样式调整
    // 可能需要使用不同的 rpx 计算基准
  }
})

// 横屏时限制最大宽度
.landscape-container {
  max-width: 750rpx;
  margin: 0 auto;
}

总结

rpx 使用要点

场景推荐单位说明
组件尺寸rpx宽度、高度、内边距、外边距
字体大小rpx统一使用变量定义的字号
圆角rpx与组件尺寸保持一致
边框px保持 1 像素清晰
图标rpx与文字字号协调
阴影rpx与组件尺寸成比例
动画transform避免直接修改 rpx 尺寸
Canvaspx需要转换为实际像素

设计稿换算表

设计稿宽度换算公式示例
750px直接使用100px → 100rpx
375px×250px → 100rpx
640px×1.17187585px → 100rpx

平台兼容性

平台rpx 支持转换方式
H5postcss 转 rem/vw
微信小程序原生支持
支付宝小程序原生支持
App (vue)运行时计算
App (nvue)⚠️建议使用 px/upx