以前做移动端项目的时候都是用 rem 来做适配,现在基本上都是通过 viewport 单位来做。 postcss-px-to-viewport 就是一个将 px 单位转换为视口单位的 (vw, vh, vmin, vmax) 的 PostCSS 插件,它可以将你 CSS 中的 px 单位转化为 vw,1vw 等于 1/100 视口宽度。
# 1. 安装
| npm install postcss-px-to-viewport --save-dev | 
# 2. 配置参数
在项目根目录创建 postcss.config.js 文件,添加如下配置。
| module.exports = ({ webpack }) => { | |
| return { | |
| plugins: { | |
| autoprefixer: {}, | |
| "postcss-px-to-viewport": { | |
| unitToConvert: "px", // 要转化的单位 | |
| viewportWidth: 750, // UI 设计稿的宽度 | |
| unitPrecision: 6, // 转换后的精度,即小数点位数 | |
| propList: ["*"], // 指定转换的 css 属性的单位,* 代表全部 css 属性的单位都进行转换 | |
| viewportUnit: "vw", // 指定需要转换成的视窗单位,默认 vw | |
| fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认 vw | |
| selectorBlackList: [], // 指定不转换为视窗单位的类名, | |
| minPixelValue: 1, // 默认值 1,小于或等于 1px 则不进行转换 | |
| mediaQuery: true, // 是否在媒体查询的 css 代码中也进行转换,默认 false | |
|                 //replace: true, // 是否转换后直接更换属性值 | |
| exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配 | |
| landscape: false // 是否处理横屏情况 | |
|             } | |
|         } | |
|     } | |
| } | 
启动项目,此时已经自动进行了转换,会根据 postcss.config.js 文件中的 viewportWidth 的值将 px 转换为 vw ,比如说设置 div 宽度为 750px,转换后就是 100vw。此时的样式如下:
输入
| .class { | |
| margin: -10px .5vh; | |
| padding: 5vmin 9.5px 1px; | |
| border: 3px solid black; | |
| border-bottom-width: 1px; | |
| font-size: 14px; | |
| line-height: 20px; | |
| } | 
输出
| .class { | |
| margin: -3.125vw .5vh; | |
| padding: 5vmin 2.96875vw 1px; | |
| border: 0.9375vw solid black; | |
| border-bottom-width: 1px; | |
| font-size: 4.375vw; | |
| line-height: 6.25vw; | |
| } | 
# 3.vant
# (1). 问题 1 vant 中组件的 css 单位没有转换
将所有的配置好之后,启动项目,添加了 vant 的组件后,打开检查,发现仍然是 px 单位,没有进行转换。
 因为
 因为 postcss.config.js 文件中的 exclude 参数将整个 node_modules 文件夹中的组件都给排除掉了,安装的插件会使用它默认的单位,将 exclude 改为 []
# (2). 问题 2 转视口单位后的 vant 组件特别小
此时 vant 组件的单位也进行了转换,但是展示会特别的小。

通过排查,在 github 上找到 vant 的官方 demo,发现 vant 设置视口宽度是 375,而我们设置的宽度为 750,所以 vant 组件在转换之后会宽高都变为原来的一半大小。

所以我们要设置当转换到 vant 组件样式的单位时,将视口宽度设置为 375,将 postcss.config.js 配置修改如下:
| const path = require("path") | |
| module.exports = ({ webpack }) => { | |
| const designWidth = webpack.resourcePath.includes(path.join("node_modules", "vant")) ? 375 : 750 | |
| return { | |
| plugins: { | |
| autoprefixer: {}, | |
| "postcss-px-to-viewport": { | |
| unitToConvert: "px", // 要转化的单位 | |
| viewportWidth: designWidth, | |
| unitPrecision: 6, // 转换后的精度,即小数点位数 | |
| propList: ["*"], // 指定转换的 css 属性的单位,* 代表全部 css 属性的单位都进行转换 | |
| viewportUnit: "vw", // 指定需要转换成的视窗单位,默认 vw | |
| fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认 vw | |
| selectorBlackList: [], // 指定不转换为视窗单位的类名, | |
| minPixelValue: 1, // 默认值 1,小于或等于 1px 则不进行转换 | |
| mediaQuery: true, // 是否在媒体查询的 css 代码中也进行转换,默认 false | |
|                 //replace: true, // 是否转换后直接更换属性值 | |
| exclude: [], // 设置忽略文件,用正则做目录名匹配 /node_modules/ | |
| landscape: false // 是否处理横屏情况 | |
|             } | |
|         } | |
|     } | |
| } | 
此时页面已经恢复了正常。

# 4. 行内样式
后续在使用 vant 的 image 组件的时候发现,在传入 width 和 height 750 之后,图片超出了页面,打开检查发现仍然是 px 单位,没有转化为 vw,传入的 width 和 height 是加到了 img 标签父元素的行内样式上,创建一个 div 实验了一下, postcss-px-to-viewport 不会对行内样式进行转换,只会转换卸载 style 标签中的样式。给 image 组件添加了 class,展示正常。
使用 width 和 height 传入:

使用 class 控制样式: 
