postcss学习

安装

  • 任意目录npm init -yes

使用这种方式,项目的名词一定不要和某些库的名词冲突,比如叫webpack,postcss,如果叫这个名词安装相关库时就会报ENOSELF的错误

  • 安装webpack

npm i --save-dev webpack webpack-cli

  • 安装postcss

npm i --save-dev postcss

  • 安装相关loader

npm i --save-dev postcss-loader

  • 安装babel相关资源(因为会通过import引入资源,所以需要安装)

npm i --save-dev babel-cli babel-preset-es2015 babel-loader

  • 安装mini-css-extract-plugin插件(这个插件是webpack4+版本用来提取css用的插件,与extract-text-webpack-plugin功能相似)

npm i --save-dev mini-css-extract-plugin

基本概念

  • postcss是一个用JS插件转换成CSS的工具
  • postcss不是预处理器

预处理器是指对css能力增强的功能,添加一些一些本身不是css的功能(比如嵌套、变量),通过处理后能转成普通的CSS,

  • postcss不是后处理器

通过一些规则把已有的css进行完善,比如添加浏览器前缀

  • postcss是作为一个平台的存在,利用postcss提供的插件可以组合各种不同模块,来构建更为复杂的功能

相关解析器

  • css-loader是可以在页面中使用import引入css的能力
  • style-loader是把css代码生成style标签,放到head标签中

使用流程

  • 新建两个文件夹

src:源文件目录
dist:输出目录

  • 在webpack.config.js中设置相关规则
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    context: path.resolve(__dirname, 'src'),
    entry: {
        mjs: './main.js',
    },
    mode: 'development',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "[name].bundle.js"
    },
    module: {
        rules: [
            {test: /\.(js|jsx)$/, use: 'babel-loader'},
            {test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader"
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            filename: "[name].css",
            chunkFilename: "[id].css"
        })
    ]
};

mini-css-extract-plugin使用的例子

从js中分离css代码

// 在src文件夹下新建main.js,base.css,color.css内容如下
// main.js
import './base.css';
import './color.css';

const base = 'main.js';
...
// base.css
body {font-size: 12px}
...
// color.css
.red {color: red}

在package.json添加如下内容

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "./node_modules/.bin/webpack --config webpack.config.js"
  },

运行npm run build,这时在dist目录下,就会看到mjs.bundle.js和mjs.css两个文件,打开mjs.css会发现里面内容就是base.css和color.css的内容

通过pcss中引入样式文件

参考上面的例子,这次我们从js把pcss的内容导出到css中

  • 安装postcss-import,使在.pcss文件可以使用@import引入样式文件

npm i --save-dev postcss-import

// 在webpack.config.js中做如下修改
{test: /\.pcss$/, use: [
    MiniCssExtractPlugin.loader,
    "css-loader",
    "postcss-loader"
]},
...
// 在src目录下新建mian.pcss
@import './base.css';
@import './color.css';
...
// main.js下做如下调整
// .pcss可以算是postcss专用格式
import './main.pcss';

const base = 'main.js';

这里修改添加一个对post的配置文件,要不运行时会报错,新建.postcssrc.js也可以叫postcss.config.js

// 暂时没有其他配置,可以把留空
module.exports = {
    plugins: []
}

运行后,发现mjs.css内容和之前打包后一致,通过这个例子我们在pcss可以import相关样式文件,下面我们安装一个常用的插件,来演示postcss的配置文件

  • 安装autoprefixer

npm i --save-dev autoprefixer

  • 修改相关配置文件.postcssrc.js

autoprefixer的参数,基本使用默认配置即可,这里只说browsers参数的设定,因为这关系到最终添加前缀的内容

// autoprefixer相关配置可以参考其官方文档
let postcssConfig = {};
postcssConfig.autoprefixer = {
    browsers: ['> 1%', 'ff 3']
}

module.exports = {
    plugins: postcssConfig
}
  • 修改main.pcss内容如下
b {
    border-radius:5px;
}

编译运行后结果为

b {
    -webkit-border-radius:5px;
       -moz-border-radius:5px;
            border-radius:5px;
}

通过这个插件我们很便捷的添加了相关浏览器私有前缀,下面讲下如何设定添加前缀的范围。

autoprefixer的插件参数browsers是利用browserslist功能来决定是否需要添加某些浏览器前缀,在browserslist的文档里我们可以找到详细设定,可以设定针对某些浏览器,或者针对国家,或者针对指定平台,下面列举下在项目中最有可能碰到的浏览器

  • Android: Android webview浏览器,一般安卓app进行混合开发,应该都有集成
  • iOS: ios的Safari浏览器
  • Chrome: 谷歌浏览器
  • ChromeAndroid: 谷歌浏览器安卓版
  • Edge: 微软的Edge浏览器
  • ie: ie浏览器
  • Safari: Safari桌面浏览器
  • ff: firefox浏览器
  • and_ff: firefox安卓浏览器
  • and_qq: QQ浏览器安卓版
  • and_uc: UC浏览器安卓版

browsers接收的是一个数组,所以可以像例子中那样分开设置,下面的话的意思就是为了适配安卓2.3,ios3.2,Safari3.1,IE10浏览器要添加相关前缀

'> 0%','Android 2.3','iOS 3.2','Safari 3.1','IE 10'

至于 > 0%是指当你不想像上面设置那么繁琐的指定浏览器时,可以直接指定个大概,就是我要支持市面上多少多少比例的浏览器,这个数字前面可以添加普通的运算符 > >= < <=

除此之外还可以加前缀修饰符not表示不在某个范围中,此外还可以使用cover extends或者since进行更细化的设置,包括道指定从哪年开始的什么版本。。。感觉把细化的有点恐怖了,就不去深究更细的设置了,基本使用上面的浏览器标识、大概覆盖范围、和特意排除某个浏览器就能完成基本的设置

如果想去掉关于firefox浏览器的设置,可以先修改支持范围,因为如果是> 0%其实就是全部浏览器支持就不存在筛选的问题

 browsers: ['> 1%']

这时在运行,其实发现加在border-radius的前缀,应该是现在市面99%浏览器都支持圆角的样式,为此可以进一步做些测试,验证这其他设置

  browsers: ['> 1%', 'ff 3']
  ...
  browsers: ['> 1%', 'ff < 4']

圆角功能是ff4才加的功能,我们指定适配某个浏览器版本,这时就会发现运行后的样式一样会有ff的私有前缀,所以一般我们结合浏览器覆盖范围,再加上对特定浏览器的排除就能完成相关设置

有一点需要注意的,设置范围时需要指定范围,不能直接设置ff或者not ff,这时编译会报错,你需要明确指明版本才可以

结合这个例子,其实也就能看出postcss其实像是一个平台,把可能功能集合到一起,通过配置文件的设置,就能指定编译器对pcss文件如何编译,下面介绍比较常用的插件,让我们可以像编写sass或者less那样编写样式

cssnext

这个插件允许开发人员在当前项目中使用css将来版本可能会加入的新特性,这个就非常类似于写ES6的代码,但是使用babel转成ES5的代码,这个插件包含的功能,一般就已经够用的了(这个插件中其实也包含了autoprefixer,使用了这个插件autoprefixer可以不安装)

  • 安装该插件

npm i --save-dev postcss-cssnext

修改postcss的配置文件

// 新增
postcssConfig['postcss-cssnext'] = {};

下面介绍cssnext中主要使用的未来语法

  • 自定义属性和变量

允许在 CSS 中定义属性并在样式规则中作为变量来使用它们。自定义属性的名称以“–”开头。当声明了自定义属性之后,可以在样式规则中使用“var()”函数来引用

// 在main.pcss样式修改为
b {
    border-radius:5px;
}

:root {
 --text-color: black;
}
 
body {
 color: var(--text-color);
}

这时运行,cssnext会报个错误,提示你autoprefixer已经被集成到cssnext中,给你报个警报,所以我们可以这么修改设置

let postcssConfig = {};
// 屏蔽单独对autoprefixer的设置,直接在cssnext进行设置
// postcssConfig.autoprefixer = {
//     browsers: ['> 1%', 'ff 3']
// }
postcssConfig['postcss-cssnext'] = {
    browsers: ['> 1%', 'ff 3']
};

module.exports = {
    plugins: postcssConfig
}

再次运行,编译后的样式文件变为

b {
    -moz-border-radius:5px;
         border-radius:5px;
}
 
body {
 color: black;
}
  • 配合自定义变量可以更加便捷的使用calc计算
:root {
  --main-font-size: 16px;
  --fontSize: 1rem;
}

body {
  font-size: var(--main-font-size);
}

h1 {
  font-size: calc(var(--main-font-size) * 2);
  height: calc(100px - 2em);
  margin-bottom: calc(
      var(--main-font-size)
      * 1.5
    )
}
h2 {
  font-size: calc(var(--fontSize) * 2);
}
...
// 转化为
body {
  font-size: 16px;
}

h1 {
  font-size: 32px;
  height: calc(100px - 2em);
  margin-bottom: 24px
}
h2 {
  font-size: 32px;
  font-size: 2rem;
}
  • 自定义媒体查询
@custom-media --small-viewport (max-width: 30em);

@media (--small-viewport) {
  h1 {font-size: 16px}
}
...
// 转码为
@media (max-width: 30em) {
  h1 {font-size: 16px}
}

最大最小宽度,可以使用>= <=代替

@custom-media --small-viewport (width >= 500px) and (width <= 1200px);

@media (--small-viewport) {
  h1 {font-size: 16px}
}
...
// 转为
@media (min-width: 500px) and (max-width: 1200px) {
  h1 {font-size: 16px}
}
  • 自定义选择器

CSS 扩展规范(CSS Extensions)中允许创建自定义选择器,可以使用@custom-selector”来定义自定义选择器

@custom-selector :--heading h1, h2, h3, h4, h5, h6;
 
:--heading {
 font-weight: bold;
}

运行后变为

h1,
h2,
h3,
h4,
h5,
h6 {
 font-weight: bold;
}
  • 样式规则嵌套

减少重复的选择器声明,通过两种方式进行嵌套:第一种方式要求嵌套的样式声明使用“&”作为前缀,“&”只能作为声明的起始位置;第二种方式的样式声明使用“@nest”作为前缀,并且“&”可以出现在任意位置

// 嵌套只能使用&开头,除非前缀有@nest
.message {
 font-weight: normal;
 & .header {
   font-weight: bold;
 }
  @nest .body & {
   color: black;
 }
}

运行后

.message {
 font-weight: normal
}
.message .header {
 font-weight: bold;
}
.body .message {
 color: black;
}
  • 使用image-set设置不同分辨率下的引用图片
// resolve是postcss-assets的功能,下面有介绍,这里我就没准备那么多张图
.foo {
    background-image: image-set(resolve('logo.jpg') 1x,
                                resolve('logo.jpg') 2x,
                                resolve('logo.jpg') 600dpi);
}
...
// become
.foo {
    background-image: url(resolve('logo.jpg'));
}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {.foo {
    background-image: url(resolve('logo.jpg'));
}
}
@media (-webkit-min-device-pixel-ratio: 6.25), (min-resolution: 600dpi) {.foo {
    background-image: url(resolve('logo.jpg'));
}
}
  • 使用color函数,设置颜色

在工作时设计师应该都会给定相关的颜色色值,很少需要前端自己来算这个值,而且为了保证整体项目的ui统一,应该统一在一处定义好项目中可能用到的所有色值,在一个统一地方进行维护,尽量避免这种还需要自己计算的情况,会造成样式不好维护的情况

a {
    color: color(red alpha(-10%));
}

a:hover {
    color: color(red blackness(80%));
}
...
// become
a {
    color: rgba(255, 0, 0, 0.9);
}

a:hover {
    color: rgb(51, 0, 0);
}
  • hwb就是把(hsv的色值转成rgb)
body {
  color: hwb(90, 0%, 0%, 0.5);
}
...
body {
  color: rgba(128, 255, 0, .5);
}
  • gray直接引用某个灰度色值
.foo {
  color: gray(85);
}
...
// become
.foo {
  color: rgb(85, 85, 85);
}
  • 允许使用4位颜色色值,这个色值会被转成rgba的色值
body {
  background: #9d9c;
}
...
// become
body {
  background: rgba(153, 221, 153, 0.8);
}
  • 允许使用新的颜色色值名词
color: rebeccapurple;
...
// become
color: #639;
  • font-variant没用过,和字体相关
  • filter和svg相关,没用过
  • initial值,用来表示某些属性的默认值,不建议用,写样式时,某个属性值应该是明确的,不要使用默认设置这种特性,不用就别设置
  • rem,会把rem转成px,兼容老版本浏览器
h1 {
  font-size: 1.5rem;
}
...
// become
h1 {
  font-size: 24px;
  font-size: 1.5rem;
}
  • :any-link快速设置:link和:visited属性,如果两者样式一致,可以直接使用
nav :any-link {
  background-color: yellow;
}
...
// become
nav :link,nav :visited {
  background-color: yellow;
}
  • :matches,理解成匹配选择器的语法糖
p:matches(:first-child, .special) {
  color: red;
}
...
// become
p:first-child, p.special {
  color: red;
}
  • :not,理解成多个not选择器的语法糖
p:not(:first-child, .special) {
  color: red;
}
...
// become
p:not(:first-child):not(.special) {
  color: red;
}
  • rga,hsl功能增强,可以接收alpha值
.div1 {
  background-color: rgb(100 222.2 100.9 / 30%);
}
.div2 {
  color: hsl(90deg 90% 70%);
  background-color: hsl(300grad 25% 15% / 70%);
}
...
// become
.div1 {
  background-color: rgba(100, 222, 101, .3);
}
.div2 {
  color: hsl(90, 90%, 70%);
  background-color: hsla(270, 25%, 15%, .7);
}
  • system-ui设置通用字体
body {
  font-family: system-ui;
}
...
// become
body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Droid Sans, Helvetica Neue;
}

暂时处在讨论中,不建议使用的特性

  • @aplly引入样式样式集
:root {
  --danger-theme: {
    color: white;
    background-color: red;
  };
}

.danger {
  @apply --danger-theme;
}
...
// 转码后
.danger {
  color: white;
  background-color: red;
}

下面介绍一些其他插件

postcss-assets

引用外部资源时,可以通过这个插件设置资源查找路径,简化在样式文件中插入图片的操作

安装

npm i --save-dev postcss-assets

在src目录下新建一个images目录,随意往其中存放一张图片(我使用的是一张logo.jpg的图片)

修改postcss配置文件,新增对postcss-assets路径的设置

// 设置loadPaths指定查找路径
postcssConfig['postcss-assets'] = {
    loadPaths: ['src/images']
}

这时如果在main.pcss的文件中,如果这么设置一个类

// 配置resolve,指定在查找路径下,搜索图片
.logo {
 background-image: resolve('logo.jpg');
}
...
// 编译后会变成,自动识别了
.logo {
 background-image: url('/src/images/logo.jpg');
}

postcss-assets还有其他几项设置,不过感觉不常用:

  • basePath: 如果.postcssrc.js不在项目的根目录可以使用这个参数就行修改,比如我这里,就是把配置文件在根目录下,这样我在设置loadPaths时,不用再去考虑其他路径的问题,可以从当前位置,直接设置图片目录为src/images,一般这种配置文件感觉放在根目录最好,这样可以很方便别人查看
  • baseUrl: 没特别弄明白这参数是什么意思,好像是在服务器运行时,设置url,不过理解不了,部署到生产环境的代码,肯定时编译后的代码,不能在线上再实时编译吧。。。
  • cachebuster: 是否设置缓存,默认是false
// 比如如果设为true,图片后就会加一串值,这个看情况添加吧
.logo {
 background-image: url('/src/images/logo.jpg?1637e45dd90');
}
  • loadPaths: 设置查找特定目录
  • relative: 和URL解析有关,没试出来做什么用的。。。使用默认的false,禁用相对url解析
  • cache: 默认为false,如果引入文件没有发生变化,则有限使用缓存文件,感觉应该和cachebuster配套使用,能提升编译速度

另外这个插件,还支持通过图片进行相关设置

  • inline是把图片转成base64文件,估计要慎用,如果图片很多的话,会影响编译速度
  • width是获取一张图片的宽度,height是获取一张图片的高度
.logo {
 background-image: inline('logo.jpg');
 width: width('logo.jpg');
 height: height('logo.jpg');
}
...
// 运行后
.logo {
 background-image: ...base64的图片
 width: 493px;
 height: 448px;
}

CSS MQPacker在必要时会将你的媒体查询成一个规则

// 如果没有安装这个插件
.widget1 {
  width: 100%;

  @media (min-width: 30em) {
    width: 50%;
  }

  @media (min-width: 60em) {
    width: 25%;
  }
}
.widget2 {
  width: 100px;

  @media (min-width: 30em) {
    width: 200px;
  }
}
...
// become
// 很明显这里关于min-width: 30em的设定是重复的了,正常应该是要进行合并
.widget1 {
  width: 100%;
}
@media (min-width: 30em) {
  .widget1 {
    width: 50%;
  }
}
@media (min-width: 60em) {
  .widget1 {
    width: 25%;
  }
}
.widget2 {
  width: 100px;
}
@media (min-width: 30em) {
  .widget2 {
    width: 200px;
  }
}

npm install --save-dev css-mqpacker

修改相关配置项

// .postcssrc.js新增下面内容,启用该插件
postcssConfig['css-mqpacker'] = {};

再次运行编译后如下

.widget1 {
  width: 100%;
}
.widget2 {
  width: 100px;
}
@media (min-width: 30em) {
  .widget1 {
    width: 50%;
  }
  .widget2 {
    width: 200px;
  }
}
@media (min-width: 60em) {
  .widget1 {
    width: 25%;
  }
}

cssnano对编译后的代码进行压缩

因为我使用的是webpack4+以上的版本,这个版本已经集成了cssnano,如果使用时提示不存在,可以通过下面进行安装

npm install --save-dev cssnano

webpack4+以上的版本,基本不需要对cssnano进行配置,直接把模式改成生产模式,打出的样式就是压缩的,如果需要配置,可以按如下修改配置文件

// 整个配置文件
let postcssConfig = {};
postcssConfig['cssnano'] = {preset: 'default'};
postcssConfig['postcss-cssnext'] = {
    browsers: ['> 1%', 'ff 3']
};
postcssConfig['postcss-assets'] = {
    loadPaths: ['src/images'],
    cachebuster: true
};
postcssConfig['css-mqpacker'] = {};

module.exports = {
    plugins: postcssConfig
}

再次运行样式代码就进行压缩了,postcss的运行是讲究顺序的

关于Rucksack的使用,Rucksack是封装了不少好的相关插件,不过这个东西毕竟不是标准,别人来看代码的时候还要对Rucksack的写法要属性才能了解是做什么的。

// 比如下面的内容,如果你不了解Rucksack会很懵,完全不了解这个是做什么的
.foo {
  font-size: responsive;
}
.bar {
  position: relative 20% auto;
}

相比较而言,我个人很推荐使用cssnext,因为cssnext基本就是实现了w3c组织定义的css新规范,这些规范在未来很有可能直接被浏览器支持,而通过cssnext的插件也会把这些功能转成现在浏览器可识别的样式代码

不建议使用 CSS模块化

我对此有比较强烈的抵触感,使用这种方式就会把重构和逻辑开发混在一起,本来重构只需要管理好自己的样式代码,现在还要把留意改动个类名是否会影响到逻辑代码

// 比如下面这些代码
:global .title {
 font-size: 20px;
}
 
.content {
 font-weight: bold;
}
...
// 如果经过转换,可能会变成
.title {
 font-size: 20px;
}
 
._content_6xmce_5 {
 font-weight: bold;
}
...
// 再借由一些其他处理,我们在页面中很可能是这样使用代码
Hello world
... // 然后转意出来后代码变为
Hello world

也就是说,现在重构在写样式时,不能再考虑修改content的类名了,因为一修改对应的header.content就找不到这个名词了,虽然在实际开发中这种场景其实并不多,重构定义好的类名也是不会随意修改的(而且也可以通过一些规范规则避免这些情况),但是这种为了解决一个问题,而可能引出另外一个问题的行为是否好呢(比如),如果按项目,页面,模块这几个维度设置好样式嵌套逻辑,是否可以很完美的解决样式组织的问题呢?

避免编译器对pcss文件报错

我使用的是我使用的是vscode,引用插件后写的样式,编译器基本是不认识的,会给你报错,所以这里说下如何避免对pcss的报错,其他编译器应该也有类似的方法

对vscode添加对.pcss文件的支持

  • 安装postcss-sugar-language插件
  • 进入setting,搜索files.associations在其中添加如下内容
"*.css": "postcss"

同时设置"postcss.validate": false,避免检查器对pcss进行检查

postcss要注意设置任务顺序,比如添加浏览器前缀,应该是要比较靠后执行的,避免有些无法前缀无法添加

你可能感兴趣的:(postcss学习)