# 移动端适配方案对比,vw和rem到底选哪个

2 阅读3分钟

做H5项目,第一件事就是确定适配方案。vw、rem、百分比、flexible.js……方案太多了,新手很容易选错。

今天把主流方案理一遍,给出明确的选择建议。

方案一:rem + 动态font-size

这是最经典的方案,早期移动端几乎都用它。

// 以750设计稿为例
function setRem() {
    const baseSize = 75; // 750 / 10
    const scale = document.documentElement.clientWidth / 750;
    document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + 'px';
}
window.addEventListener('resize', setRem);
setRem();
/* 设计稿上100px的元素 */
.box {
    width: calc(100 / 75 * 1rem);  /* 或直接用postcss转换 */
}

缺点:需要JS介入,字体大小不好控制,容易出现"字体缩放后模糊"的问题。

方案二:vw

vw是相对视口宽度的单位,1vw = 视口宽度的1%。纯CSS方案,不需要JS。

/* 750设计稿,1px = 100/750 vw */
.box {
    width: 13.3333vw;   /* 设计稿100px */
    height: 6.6667vw;   /* 设计稿50px */
}

实际项目里用PostCSS自动换算:

npm install postcss-px-to-viewport -D
// postcss.config.js
module.exports = {
    plugins: {
        'postcss-px-to-viewport': {
            viewportWidth: 375,       // 设计稿宽度
            unitPrecision: 5,
            viewportUnit: 'vw',
            selectorBlackList: ['.ignore-'],  // 不转换的类名
            minPixelValue: 1,
            mediaQuery: false
        }
    }
};

写代码时还是写px,构建时自动转成vw,体验很好。

方案三:flexible + rem(阿里方案)

amfe-flexible是阿里出的方案,本质还是rem,但处理了dpr和1px边框问题:

import 'amfe-flexible';
// postcss-pxtorem
{
    rootValue: 37.5,
    propList: ['*'],
    selectorBlackList: ['.norem']
}

这个方案的优点是生态成熟,缺点是依赖JS,而且新版amfe-flexible已经不怎么维护了。

方案四:媒体查询 + 百分比

.container {
    width: 100%;
    max-width: 750px;
    margin: 0 auto;
}

.box {
    width: 50%;
}

@media (min-width: 768px) {
    .box { width: 33.33%; }
}

这个方案适合内容型页面(文章、列表),不适合精细的视觉还原。

对比总结

方案依赖JS精度维护性适合场景
rem + JS是高一般老项目、精细还原
vw否高好新项目首选
flexible是高一般需要处理1px问题
百分比否低好内容型页面

我的建议

新项目直接用vw。 理由:

  1. 纯CSS,不需要JS,首屏不会闪
  2. PostCSS自动转换,开发体验和写px一样
  3. 兼容性已经很好(iOS 9+、Android 4.4+)
  4. 不需要处理font-size的边界问题
// 完整的postcss配置
module.exports = {
    plugins: {
        'postcss-px-to-viewport-8-plugin': {
            unitToConvert: 'px',
            viewportWidth: (file) => {
                // 区分PC和移动端
                if (file.indexOf('pc') !== -1) return 1920;
                return 375;
            },
            unitPrecision: 5,
            viewportUnit: 'vw',
            fontViewportUnit: 'vw',
            selectorBlackList: ['.pc-'],
            minPixelValue: 1,
            mediaQuery: false,
            replace: true,
            exclude: [/node_modules/]
        }
    }
};

需要注意的几个坑

1. 1px边框问题

在2倍屏上,1px会被渲染成2个物理像素。解决方案:

.border {
    border: 1px solid #ddd;
}

@media (-webkit-min-device-pixel-ratio: 2) {
    .border {
        border-width: 0.5px;
    }
}

2. 字体大小不要用vw

标题字号用vw在超宽屏上会大得离谱,可以用clamp:

.title {
    font-size: clamp(18px, 4vw, 28px);
}

3. 大屏限制

移动端页面在PC上打开会拉伸变形,加个最大宽度:

#app {
    max-width: 750px;
    margin: 0 auto;
}

适配方案没有银弹,vw在绝大多数场景下够用。真遇到特殊需求,混用方案也不丢人。