Skip to content

本章主要介绍,目前常用的一些第三方插件。

较为完整的插件列表可以参考PostCSS Plugins

autoprefixer

autoprefixer 可以为 CSS 属性自动添加 prefix 前缀。

譬如 CSS3 中的 flex 布局、或者 transform 转换等。

该插件由于跟目标浏览器的版本相关,因此需要在项目根目录下配置 .browserslistrc、或者在 package.json 文件下添加 browserslist 字段

譬如:

> 1%
last 2 versions
not ie <= 8
# not dead => IE 10 has been dead
json
{
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

如果使用该插件的过程中, CSS 没有出现对应前缀,那么可以使用 npx autoprefixer --infodebugger

也可以利用 JS 的形式,console.log(autoprefixer().info())

postcss-import

postcss-importCSS 文件中,可以使用 @import url() 语法。

譬如:

css
/* entry.css */
@import url(./flex.css);
@import url(./transform.css);
css
/* flex.css */
.flex {
  display: flex;
}
css
/* transform.css */
.container {
  transform: scale(2);
  user-select: none;
}

添加 postcss-import 插件后,@import url() 语句便能够正常解析,从而将 flex.csstransform.css 中的内容整合到 entry.css 中。

postcss-url

postcss-url 可以用来处理 CSS 中的图片。

譬如,将 CSS 中的图片转换为 base64 形式:

css
.avatar {
  width: 80px;
  height: 80px;
  background-image: url('../img/avatar.jpeg');
  background-size: 100% 100%;
}
js
// .postcssrc.js
const autoprefixer = require('autoprefixer')
const postcssImport = require('postcss-import')
const postcssUrl = require('postcss-url')

module.exports = ctx => {
  return {
    plugins: [
      autoprefixer({}),
      postcssImport({}),
      postcssUrl({
        url: 'inline'
      })
    ]
  }
}

postcss-pxtorem

postcss-pxtorem 可以用来将项目中的 px 单位自动转换为 rem

默认转换比例为 1 : 16,即 1rem = 16px

在实际项目中,通常会与 lib-flexible 结合使用:

js
const autoprefixer = require('autoprefixer')
const postcssImport = require('postcss-import')
const postcssUrl = require('postcss-url')
const postcssPxToRem = require('postcss-pxtorem')

module.exports = ctx => {
  return {
    plugins: [
      autoprefixer({}),
      postcssImport({}),
      postcssUrl({}),
      postcssPxToRem({
        // 默认 16,即1rem = 16px。如果结合lib-flexible的话,以375设计稿为例。lib-flexible会将html的font-size设置为375 / 10 即37.5,则此处应对应修改。
        rootValue: 40,
        // 设定最小px值 当目标值小于该值时,不进行rem转换。通常,不转换字体图标。
        minPixelValue: 2,
        // 指定哪些属性进行rem转换,如font-size、width等,设置为*,代表所有属性均可进行转换。
        propList: ['*'],
        // 选择器黑名单 当目标元素使用了黑名单选择器,则该选择器下的属性,不进行rem转换。
        selectorBlackList: []
      })
    ]
  }
}

postcss-px-to-viewport

postcss-px-to-viewport 可以用来将 px 单位自动转换为 vw

该方式是lib-flexible@2.0靠近且推荐的实现。

但是在 2023 年的笔者看来,在实际项目中使用 postcss-px-to-viewport,依然有待商榷。

相比之下,笔者依然推荐lib-flexible@1.0结合postcss-pxtorem,操作很方便且简单易行,最重要的是设置了最大参考宽度为 540px,在大屏上不会过大

以下简单记录下 postcss-px-to-viewport 的引入方式和使用方法:

js
const autoprefixer = require('autoprefixer')
const postcssImport = require('postcss-import')
const postcssUrl = require('postcss-url')
const postcssPxToViewport = require('postcss-px-to-viewport')

module.exports = ctx => {
  return {
    plugins: [
      autoprefixer({}),
      postcssImport({}),
      postcssUrl({}),
      postcssPxToViewport({
        unitToConvert: "px", // 要转化的单位
        viewportWidth: 750, // UI设计稿的宽度
        unitPrecision: 6, // 转换后的精度,即小数点位数
        propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
        viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
        fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
        selectorBlackList: ["wrap"], // 指定不转换为视窗单位的类名,
        minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
        mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
        replace: true, // 是否转换后直接更换属性值
        exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
        landscape: false // 是否处理横屏情况
      })
    ]
  }
}

postcss-nesting

postcss-nesting是基于[CSS官网嵌套规范]而制定的插件。

css
.foo {
	color: red;

	&:hover {
		color: green;
	}

	> .bar {
		color: blue;
	}

	@media (prefers-color-scheme: dark) {
		color: cyan;
	}

	color: pink;
}

/* becomes */

.foo {
	color: red;

  color: pink;
}
.foo:hover {
  color: green;
}
.foo > .bar {
  color: blue;
}
@media (prefers-color-scheme: dark) {
  .foo {
    color: cyan;
  }
}

postcss-nested

postcss-nested则是基于[Sass]嵌套规范而制定的插件。

css
.phone {
  &_title {
    width: 500px;
    @media (max-width: 500px) {
      width: auto;
    }
    body.is_dark & {
      color: white;
    }
  }
  img {
    display: block;
  }
}

.title {
  font-size: var(--font);

  @at-root html {
      --font: 16px
  }
}

/* Becomes */
.phone_title {
  width: 500px;
}
@media (max-width: 500px) {
  .phone_title {
    width: auto;
  }
}
body.is_dark .phone_title {
  color: white;
}
.phone img {
  display: block;
}

.title {
  font-size: var(--font);
}
html {
  --font: 16px
}

postcss-preset-env

postcss-preset-env 是基于 browserslist 的样式预设。

所有的属性支持可以在CSSDB中查看。

如果目标浏览器不支持某 CSS 属性,则 postcss-preset-env 会尝试提供 JavaScript 版本的 polyfill 以实现 CSS 设置。

另外,要注意的一点是,postcss-preset-env 内置了 autoprefixer 功能

譬如有如下配置:

js
// const autoprefixer = require('autoprefixer')
const postcssImport = require('postcss-import')
const postcssUrl = require('postcss-url')
const postcssPresetEnv = require('postcss-preset-env')

module.exports = ctx => {
  return {
    plugins: [
      // autoprefixer({}),
      postcssImport({}),
      postcssUrl({
        url: 'inline'
      }),
      postcssPresetEnv()
    ]
  }
}

.browserslistrc 文件内容如下:

> 1%
last 2 versions
# not dead => IE 10 has been dead
not ie <= 8

则以下 entry.css

css
/* entry.css */
@custom-media --viewport-medium (width <= 50rem);
@custom-selector :--heading h1, h2, h3, h4, h5, h6;

:root {
  --mainColor: bisque;
}

html, body {
  width: 100%;
  height: 100%;
  background-color: var(--mainColor);
  font-family: system-ui;
  overflow-wrap: break-word;
}

:--heading {
  @media (--viewport-medium) {
    margin-block: 0;
  }
}

a {
  color: rgb(0 0 100% / 90%);

  &:hover {
    color: rebeccapurple;
  }
}

会被转换成如下 output.css

css
@custom-selector :--heading h1, h2, h3, h4, h5, h6;
:root {
  --mainColor: bisque;
}
html, body {
  width: 100%;
  height: 100%;
  background-color: bisque;
  background-color: var(--mainColor);
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
  word-wrap: break-word;
}
:--heading {
  @media (max-width: 50rem) {
    margin-top: 0;
    margin-bottom: 0;
  }
}
a {
  color: rgba(0, 0, 255, 0.9);

  &:hover {
    color: #639;
  }
}