背景
Vue 2 项目要做移动端,设计稿通常是 750px 宽。每次写样式时都要算"设计稿 32px 等于实际多少 rem",效率太低。用 lib-flexible + postcss-px2rem 这套组合,代码里直接写 px,运行时自动适配各种屏幕。
注:lib-flexible 在 Vue 3 项目里改用 amfe-flexible + postcss-pxtorem,本文是 Vue 2 + Webpack 老项目方案。

装两个包
npm install lib-flexible postcss-px2rem --save
两个包的作用:
lib-flexible:运行时,根据 viewport 宽度动态设置html的font-size。屏幕 750px 时根字号 75px,屏幕 375px 时 37.5px,以此类推。postcss-px2rem:构建时,扫描所有 CSS 把px除以remUnit转成rem。
项目 package.json 参考
{
"name": "XiaoDong",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^1.3.2",
"core-js": "^3.25.3",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"lib-flexible": "^0.3.2",
"pinia": "^2.0.32",
"pinia-plugin-persist": "^1.0.0",
"postcss-px2rem": "^0.3.0",
"qrcode": "^1.5.1",
"vant": "^2.12.53",
"vue": "^2.7.0",
"vue-canvas-poster": "^1.2.1",
"vue-cookies": "^1.8.2",
"vue-moment": "^4.1.0",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.19",
"@vue/cli-plugin-router": "~4.5.19",
"@vue/cli-plugin-vuex": "~4.5.19",
"@vue/cli-service": "~4.5.19",
"babel-plugin-import": "^1.13.6",
"prettier": "2.8.4",
"vue-template-compiler": "^2.7.0"
}
}
main.js 引入 flexible
项目入口顶上加一行:
// src/main.js
import 'lib-flexible'
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
这一行 import 后,lib-flexible 自动接管 html 的 font-size 和 meta[name=viewport]。打开浏览器看 <html> 元素,会发现它的 style="font-size: 37.5px;" 之类的属性(根据屏幕动态调整)。
vue.config.js 配置 px2rem
// vue.config.js
module.exports = {
publicPath: '/vote/',
css: {
loaderOptions: {
css: {},
postcss: {
plugins: [
require('postcss-px2rem')({
remUnit: 37.5
})
]
}
}
}
}
remUnit 怎么定:
- 用 Vant 2.x 之类的 UI 库 →
remUnit: 37.5(Vant 内部就是按 37.5 设计的,要对齐) - 纯手写 / 设计稿 750px →
remUnit: 75 - 设计稿 1080px →
remUnit: 108
规则:remUnit = 设计稿宽度 ÷ 10。Vant 用 37.5 是因为它内部以 375px 为基准(iPhone 6/7/8 的 viewport)。
使用示例
配置完成后,直接写 px 就行,不用手动算 rem:
<template>
<div class="card">
<h2 class="title">商品标题</h2>
<p class="price">¥99.00</p>
</div>
</template>
<style lang="less" scoped>
.card {
padding: 20px; /* 自动转 rem,屏幕宽度等比缩放 */
background: #fff;
border-radius: 8px;
}
.title {
font-size: 32px; /* 自动转 rem */
color: #333;
}
.price {
font-size: 28px;
color: #ee0a24;
margin-top: 12px;
}
</style>
构建出来 32px 在 remUnit: 37.5 下,会变成 32 / 37.5 ≈ 0.853rem。再乘以运行时 html font-size(动态值),就是最终像素值。
不想转的怎么办(白名单)
有些场景不想转,比如 border: 1px solid #eee 这种 hairline 边框,转 rem 后在 hidpi 屏会糊。
解决:在 px 后面加 /*no*/ 注释,px2rem 看到就不转:
.line {
border-top: 1px solid #eee; /* 会被转成 0.026rem,糊 */
border-top: 1px /*no*/ solid #eee; /* 不转,保留 1px */
}
更全局的做法用 postcss-px2rem-exclude 配置黑名单文件夹,但项目级里 /*no*/ 注释最灵活。
常见坑
1. flexible 没生效,字体不缩放
- 检查 main.js 里
import 'lib-flexible'是否在最顶部 - F12 看
html元素,style 里有没有font-size。没有就是 lib-flexible 没跑起来
2. iPhone 横屏字超大
横屏 viewport 变成 667px,根字号变 66.7px,所有元素都翻倍。解决:CSS 里用媒体查询固定大屏字号:
@media screen and (orientation: landscape) and (max-width: 1024px) {
html { font-size: 37.5px !important; }
}
3. 1px 边框在 iPhone 上变粗
这是 hidpi 屏的问题,跟 flexible 无关。解决用 transform: scale(0.5) 伪元素技巧,或者 Vant 自带的 hairline 组件。
Vue 3 / Vite 项目的替代
新项目不推荐 lib-flexible + postcss-px2rem 这套(俩包都不再维护)。改用:
npm install amfe-flexible postcss-pxtorem --save
Vite 配置:
// vite.config.ts
import postcssPxToRem from 'postcss-pxtorem'
export default defineConfig({
css: {
postcss: {
plugins: [
postcssPxToRem({
rootValue: 37.5,
propList: ['*'],
minPixelValue: 2
})
]
}
}
})
API 几乎一样,但用的是社区还在维护的版本。
—— 别看了 · 2026