如今面向移动端的网页开发中,会经常使用到 viewport(vw、vh) 作为单位,如果网页中的元素全部使用 vw 作为单位,那么整个网页就可以像图片一样实现跟随设备宽度自行缩放变化的效果,大大简化了移动端适配的工作。

不过很多前端组件库,他们实现样式的时候,仍然还是使用的 px 作为单位,仅仅我们自己实现的元素改为 vw,效果并不完美。下面就以 Vue CLI / Vite 项目为例,介绍一种能在打包时,自动将 Vant 组件库中的 px 转换为 vw 的方法。

Vue CLI

安装 postcss-px-to-viewport

Vue CLI 已经安装过了 PostCSS,所以我们这里只需要安装所需的插件即可

npm install -s postcss-px-to-viewport

配置

如果只是简单的把 Vant 的 px 转换为 vw,并且也不在意自己的代码中的 px 也被转换为 vw 的话,那可以直接修改 vue.config.js 来配置:

// vue.config.js
const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  css:{
    loaderOptions:{
      postcss: {
        postcssOptions: {
          plugins: {
            'postcss-px-to-viewport': {
              unitToConvert: 'px', // 需要被插件转换的单位,配置后,项目里所有的 px 单位都会被转换
              viewportWidth: 375, // 100vw 对应的 unit 数量,这里代表着 375px == 100vw,这里使用这个值的缘阴是,Vant 的 px 就是按照 100% 屏幕宽度为 375px 设计的。
            },
          },
        },
      },
    },
  },
});

上面的配置可以满足基本的需要,不过目前不少设计规范,会要求设计给出 750px 的设计稿,和 Vant 的 375 并不兼容,那么有没有什么办法,能让不同的文件根据不同的 viewportWidth 转换呢?这就需要用到 .postcssrc 了,也就是我们直接修改 PostCSS 的配置文件,这样可以获得更高的自由度:

// 在 vue.config.js 同目录下,新建一个叫 .postcssrc.js 的文件,内容如下
// https://github.com/michael-ciniawsky/postcss-load-config
const path = require('path');

module.exports = (options) => {
  const { file } = options; // 获取当前在处理的文件的路径,不同的 webpack 版本获取方式不同,可以自行查看 options 的结构,找到对应的位置。
  const isVant = file.includes(path.join('node_modules', 'vant')); // 通过 file 判断是否是 Vant 下的文件
  const viewportWidth = isVant ? 375 : 750; // 如果是 Vant 下的,那么将 viewportWidth 设置为 375,否则为 750
  const unitToConvert = isVant ? 'px' : 'rpx'; // 如果是 Vant 下的,那么转换 px,否则转换 rpx(这个 rpx 我们稍后再提)
  return {
    plugins: {
      'postcss-px-to-viewport': {
        unitToConvert,
        viewportWidth,
      },
    },
  };
};

rpx 的意义

rpx 这个单位,有微信小程序开发经验的应该很熟悉,它其实也是一个相当单位,与 vw 作用类似,转换关系为 750rpx == 100vw,之所以将 unitToConvert 设置为 rpx 来引入这个东西,本质上为了保留 px 的原始用法,如果真的出现了一个就是要固定 px 的场景,那么我们仍然还可以继续用 px,而我们日常开发中,就可以很放心的使用 rpx 单位了。

Vite

安装 postcss-px-to-viewport

Vite 已经安装过了 PostCSS,所以我们这里只需要安装所需的插件即可

npm install -s postcss-px-to-viewport

配置

如果只是简单的把 Vant 的 px 转换为 vw,并且也不在意自己的代码中的 px 也被转换为 vw 的话,那可以直接修改 vite.config.js 来配置:

// vite.config.js
import PostcssPxToViewport from 'postcss-px-to-viewport';

// https://vitejs.dev/config/
export default defineConfig({
  css: {
    postcss:{
      plugins: [
        new PostcssPxToViewport({
            unitToConvert: 'px', // 需要被插件转换的单位,配置后,项目里所有的 px 单位都会被转换
            viewportWidth: 375, // 100vw 对应的 unit 数量,这里代表着 375px == 100vw,这里使用这个值的缘阴是,Vant 的 px 就是按照 100% 屏幕宽度为 375px 设计的。
        }),
      ],
    },
  },
});

不过相当可惜的是 Vite 下的 .postcssrc.js 内,不再能通过原来的方法获取当前在处理的 css 文件的目录了,也就没办法通过上面的方法来设置不同的 viewportWidth 了。