「rem」VS「vw」终极对决:前端移动端适配的最佳实践全解析

288 阅读5分钟

一、方案原理与实现细节

1. rem + lib-flexible(pxtorem)

  • 原理:通过 JS(如 lib-flexible)动态设置 <html> 的 font-size,PostCSS 插件(如 postcss-pxtorem)将 CSS 中 px 转 rem,实现自适应。
  • 实现
    • 引入 lib-flexible,监听页面宽变化,动态调整根字体。
    • CSS 书写 px,构建时自动转 rem。
    • 适合兼容老设备、字体缩放需求强的场景。

2. vw + postcss-px-to-viewport

  • 原理:利用 CSS 的 vw 单位(视口宽度百分比),PostCSS 插件自动将 px 转 vw,无需 JS。
  • 实现
    • 配置 postcss-px-to-viewport 插件,无需引入额外 JS。
    • CSS 直接写 px,构建时自动转 vw。
    • 只需设置好 viewport meta 标签即可。
    • 适合现代移动端、响应式需求强的项目。

二、 安装使用步骤

rem 方案详细使用步骤

  1. 安装依赖

通常需要 postcss-pxtorem 插件:

npm install postcss-pxtorem --save-dev
  1. 配置 PostCSS

postcss.config.jsvite.config.js 中添加:

module.exports = {
  plugins: {
    'postcss-pxtorem': {
      rootValue: 37.5, // 设计稿宽度375px时,1rem=37.5px
      propList: ['*'], // 需要转换的属性
      exclude: /node_modules/i // 排除第三方库
    }
  }
}
  1. 设置 html 根字体大小

在入口 JS 文件(如 main.jsindex.js)动态设置:

function setRemUnit() {
  const docEl = document.documentElement;
  const width = docEl.clientWidth;
  docEl.style.fontSize = (width / 10) + 'px'; // 设计稿375px时,1rem=37.5px
}
setRemUnit();
window.addEventListener('resize', setRemUnit);
  1. 样式书写规范
  • 设计稿标注单位全部用 px,开发时直接写 px,插件会自动转换为 rem。
  • 字体大小、间距、宽高等都用 px 单位。
  1. 注意事项
  • 需保证所有页面都引用了动态设置 rem 的 JS 代码。
  • 适配多端时,需根据不同设计稿宽度调整 rootValue。

vw 方案详细使用步骤

  1. 安装依赖

推荐使用 postcss-px-to-viewport 插件:

npm install postcss-px-to-viewport --save-dev
  1. 配置 PostCSS

postcss.config.jsvite.config.js 中添加:

module.exports = {
  plugins: {
    'postcss-px-to-viewport': {
      unitToConvert: 'px',
      viewportWidth: 375, // 设计稿宽度
      unitPrecision: 6,
      propList: ['*'],
      viewportUnit: 'vw',
      fontViewportUnit: 'vw',
      selectorBlackList: ['.ignore', '.hairlines'],
      minPixelValue: 1,
      mediaQuery: false,
      replace: true,
      exclude: [/node_modules/],
      landscape: false
    }
  }
}
  1. 样式书写规范
  • 设计稿标注单位全部用 px,开发时直接写 px,插件会自动转换为 vw。
  • 字体大小、间距、宽高等都用 px 单位。
  1. viewport 设置

index.html<head> 中添加:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  1. 特殊场景处理
  • 某些第三方组件或不希望被转换的样式,加上 .ignore 类名或配置 selectorBlackList
  • 1px 问题可用伪类或媒体查询单独处理。
  1. 注意事项
  • vw 方案无需 JS 动态设置根字体,纯 CSS 方案,性能更优。
  • 设计稿宽度需与 viewportWidth 保持一致。

通过上述详细步骤,你可以根据项目需求选择 rem 或 vw 方案,快速实现高效的移动端适配。


三、优缺点深度对比

维度rem + lib-flexiblevw + postcss-px-to-viewport
兼容性优,适合老设备略逊,主流设备无忧
性能JS 参与,略低纯 CSS,极优
开发体验换算繁琐,维护成本高书写直观,维护简单
首屏体验可能闪烁/抖动无闪烁,加载即适配
响应式需配合媒体查询天生响应式,灵活
字体缩放支持系统缩放不支持,需额外处理
生态趋势传统方案,逐步被替代新主流,生态持续壮大
1px 问题需特殊 hack依然需特殊 hack
适配第三方库需统一 rem 方案需统一 px 转换

rem + lib-flexible 优点

  • 兼容性极佳,适合老旧设备
  • 字体缩放友好,适合无障碍场景
  • 生态成熟,工具链完善
  • 灵活性高,可动态调整根字体

rem + lib-flexible 缺点

  • 依赖 JS,首屏闪烁风险
  • 维护成本高,需关注 JS 逻辑
  • rem 计算不直观,易出错
  • 性能略逊,1px 问题需特殊处理

vw + postcss-px-to-viewport 优点

  • 纯 CSS,无 JS 依赖,性能优
  • 开发体验极佳,维护简单
  • 响应式更灵活,适合多端适配
  • 生态趋势,未来主流
  • 特殊处理灵活,支持 selectorBlackList/注释等

vw + postcss-px-to-viewport 缺点

  • 极个别老浏览器兼容性略差
  • 设计稿需与 viewportWidth 对齐
  • 字体缩放不友好,需额外适配
  • 1px 问题依然存在
  • 第三方组件库适配难度略高

三、配置与实战案例

vw 方案配置示例

import postcsspxtoviewport from 'postcss-px-to-viewport'
css: {
  postcss: {
    plugins: [
      postcsspxtoviewport({
        viewportWidth: 375, // 设计稿宽度
        selectorBlackList: ['ignore-'], // 忽略转换
      })
    ]
  }
}

vw 方案 CSS 示例

.adaptive-box { width: 375px; } /* 自动转为100vw */
.ignore-adaptive-text { font-size: 16px; } /* 不会被转换 */
// 部分代码未展示

组件引入示例

import AdaptiveDemo from './components/AdaptiveDemo'
function App() {
  return (
    <div className="App">
      <AdaptiveDemo />
    </div>
  )
}

效果展示

移动端适配.gif


四、真实开发案例

  • 某大型商城老项目,因需兼容 Android 4.x,采用 rem 方案,维护成本高,后期逐步迁移到 vw。
  • 某新零售小程序,直接用 vw 方案,开发效率提升30%,页面性能显著提升。
  • 某无障碍阅读类 App,仍坚持 rem 方案,因需支持用户字体缩放。

五、推荐建议与总结

  • 老项目、兼容性优先、字体缩放需求强:rem + lib-flexible
  • 新项目、追求性能与开发效率、响应式需求强:vw + postcss-px-to-viewport

rem 方案像“老干部”,稳重但啰嗦;vw 方案像“新新人类”,高效又时髦。选谁?看你项目需求和团队风格啦!