postcss学习

作者: li4065 | 来源:发表于2018-05-25 10:05 被阅读583次

    安装

    • 任意目录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;
    }
    ...
    // 再借由一些其他处理,我们在页面中很可能是这样使用代码
    <div css-module="header.content">Hello world</div>
    ...
    // 然后转意出来后代码变为
    <div class="_content_6xmce_5">Hello world</div>
    

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

    避免编译器对pcss文件报错

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

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

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

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

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

    相关文章

      网友评论

        本文标题:postcss学习

        本文链接:https://www.haomeiwen.com/subject/ybryjftx.html