移动端视口适配(px → vw)

lishihuan大约 3 分钟

移动端视口适配(px → vw)

方案postcss-mobile-forever(设计宽 375vw),不依赖 html 基准字号 / rem。
设计稿:本项目按 375 × 812(宽 375 参与换算;高 812 仅作布局参考)。
用途:日常开发约定 + 下个项目复用清单。与 rem 方案(如 LegacyApp amfe-flexible)二选一,勿混用。


1. 原理(怎么对上设计稿)

开发时按设计稿标注写 px;构建期插件把 #app 内样式的 px 转成 vw;真机按屏宽缩放。

设计稿量到 44px
  → 源码写 height: 44px
  → 构建后 ≈ height: 11.733vw   (44 / 375 × 100)
  → 屏宽 375 时 ≈ 44px(对稿)
  → 屏宽 414 时略放大
  → 屏宽 > 600 时按 maxDisplayWidth 封顶,不再继续涨

公式:

vw值 = 设计稿px / viewportWidth × 100
真机 CSS 像素 ≈ (vw值 / 100) × min(屏宽, maxDisplayWidth)

为何不用基准字号:本方案缩放单位是 视口宽度(vw),不是 rem。html { font-size: 14px } 只是正文默认字号,同样会被转成 vw,不是 rem 根基准。


2. 本仓库关键文件

文件职责
postcss.config.tsviewportWidth: 375maxDisplayWidth: 600、fixed 选择器、exclude
src/utils/inline-px-to-vw.ts行内 :style 用(PostCSS 转不到动态 style)
uno.config.tsUnoCSS rem → px(createRemToPxProcessor),再交给 PostCSS 转 vw
index.htmlviewport meta(device-width + 禁缩放 + viewport-fit=cover
src/styles/app.less全局重置;默认字号写 px
src/config/layout.ts顶栏 / TabBar 高度常量(源码仍为设计稿 px)

依赖:postcss-mobile-foreverautoprefixer(见 package.json)。


3. 日常怎么写(约定)

场景做法
Less / CSS / SFC <style>直接写设计稿 px(如 width: 120px
UnoCSS 原子类正常使用;由 rem→px→vw 链路处理
:style / JS 动态尺寸使用 vw(n)n 为设计稿 px
第三方固定布局(如 VForm)postcss.config.tsexclude
1px 发丝线尽量交给插件 border: true;特殊情况单独处理

禁止

  • 同时接入 amfe-flexible / postcss-pxtorem(与 vw 方案冲突)
  • html 上设动态 fontSize = 屏宽/10 当 rem 基准
  • 行内样式手写死 px 却期望随屏缩放(须走 vw()
  • 设计稿是 750 宽时在源码写 750 而不 ÷2(本仓约定写 375 标注

4. 行内 vw() 口径

与 PostCSS 同口径(改一处必须改另一处):

// src/utils/inline-px-to-vw.ts
const idealWidth = 375   // = postcss viewportWidth
const maxWidth = 600     // = postcss maxDisplayWidth

// 输出示例:min(3.2vw, 19.2px)
export default function vw(n: number) { /* ... */ }
<div :style="{ marginTop: vw(12) }" />

5. fixed / 弹层

position: fixed 的包含块有时不是 #app。新增全屏浮层、自定义底栏时,把选择器加入 postcss.config.tsrootContainingBlockSelectorList,然后 重启 dev(该文件不支持热更新)。

当前已登记:.van-tabbar.van-popup 及四向弹出修饰类。


6. 安全区(与 vw 无关,App 必做)

  • viewport 含 viewport-fit=cover
  • 顶栏:padding-top: env(safe-area-inset-top)(见 App.vue
  • 底栏:Vant safe-area-inset-bottomenv(safe-area-inset-bottom)

7. 自测清单

  1. width: 375px 块 → 真机接近 整屏宽(未超 max)
  2. height: 44px → 375 宽设备上量约 44
  3. 桌面拉宽到 > 600 → 尺寸不再继续放大(封顶)
  4. viewportWidth / maxDisplayWidth重启,再验 1~3
  5. 行内 :stylevw() 与样式表尺寸观感一致

8. 下个项目复用步骤

  1. 定设计宽:仅一个数(本方案推荐 375;若稿为 750,标注 ÷2 再写代码)
  2. 安装pnpm add -D postcss-mobile-forever autoprefixer
  3. 复制 postcss.config.ts:改 viewportWidth / maxDisplayWidth / exclude / fixed 列表
  4. viewport metawidth=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover
  5. 复制 inline-px-to-vw.tsidealWidth / maxWidth 与 PostCSS 对齐
  6. (可选)UnoCSS:createRemToPxProcessor,避免原子类 rem 与 vw 打架
  7. 安全区 + 业务写 px;动态尺寸走 vw(n)
  8. 按 §7 自测

最小文件清单:postcss.config.* + viewport meta + vw() 工具(数字对齐)。


9. 与 rem 方案对照(选型)

本方案 px→vwrem(flexible + pxtorem)
根字号不需要必须动态设 html.fontSize
设计稿375 写 375常 750 + 双 rootValue(业务 / Vant)
大屏maxDisplayWidth 封顶需自行限制 rem
行内vw()自行转 rem
适用375 稿、Vant 4、本模板历史 750 稿项目

本仓库设计稿为 375×812固定采用本方案,不迁移 rem。


变更记录

  • 2026-07-17:成文;明确保留 postcss-mobile-forever,不以 LegacyApp rem 替换;补充复用步骤与自测