PostCss

PostCss是什么鬼

有人说是css预处理器巴拉扒拉,简略的说,PostCss是一个工具,提供了一坨插件用来转化样式。


PostCss是一个Node.js的module,将css解析成一个 AST(abstract syntax tree抽象语法树),通过任意插件解析AST并转换成string输出到一个文件中。插件可能改变AST,也可能能不改变AST。其中的变化通过生成sourcemaps去追踪。

PostCss不会改变你的css,有可能改变样式的是插件。开发者可以通过AST提供的接口来编写插件。so 不要被PostCss的名字误导,以为是和Sass之类的预处理器(preprocessors)对应的后处理器(postprecessors)。有小伙伴会问了,pre 和 post-processing的区别是什么呢?

css preprocessing postprocessing

来自维基百科的官方解释

预处理器是程序中处理输入数据,产生能用来输入到其他程序的数据的程序。

我觉得用人话解释的话,css preprocessing是指对某些代码进行解析,最终编译成css。 postprocessing 是对css进行处理,并最终生成css。

postcss plugins里 可以按照这两个维度进行分类。

比如下面隆重介绍普遍被使用的PostCss的插件 autoprefixer,这是一个比较典型的postprecessor。

autoprefixer的作用是 解析css rules,通过Can I Use 网站提供的值来添加浏览器前缀。

codepen

    a {
        display: flex
    }

处理后

    a {
        display: -webkit-box;   
        display: -webkit-flex;
        display: -ms-flexbox;
        display: flex
    }

autoprefixer 同样可以移除不必要的浏览器厂商前缀

    a {
        -webkit-border-radius: 5px;
        border-radius: 5px
    }

处理后

    a {
        border-radius: 5px
    }

有熟悉sass语法的同学们应该想到了,使用了autoprefixer以后 我们不必再使用@mixin来定义一坨添加浏览器厂商前缀方法。而是直接写不带厂商前缀的简单样式,插件会自动帮你添加你想要的。

scss语法 在线编译网站

   //yo的处理方法
    $setting:(
        is-vendor-prefix:true,
        vendor-prefix:-webkit- -ms-
    );

    @mixin prefix($property, $value) {
        // 是否开启厂商前缀支持
        @if map-get($setting, is-vendor-prefix) {
            // 遍历输出厂商代码
            @each $vendor in map-get($setting, vendor-prefix) {
                #{$vendor}#{$property}: $value;
            }
        }
        #{$property}: $value;
    }

    a {
        @include prefix(display,flex)
    }

编译成css

    a {
        -webkit-display: flex;
        -ms-display: flex;
        display: flex;
    }

我的天 通过autoprefixer, 我们可以省略这么多复杂的套路!

autoprefixer使用Browserslist。推荐使用browsersList config or package.json 这样浏览器配置就能被别的工具所分享。具体配置参考browserslist。

接下来在介绍一个preprocessor plugin precss

demo

precss 提供了一个插件包 提供类似sass的语法特性。包含

  • 嵌套 类似sass语法,可以使用&连接符来代替父元素

        .test {
            width: 100%;
            &::before {
                content: '';
            }
    
        }
  • 变量 类似sass语法 将$在变量前面,:加在值前面

        $text_color: #333;
    
        body {
            color: $text_color
        }
    
  • 条件判断 类似sass语法,使用@if@else

        $column_layout:2;
        .column {
            @if $column_layout == 2 {
                width: 50%;
    
            } @else {
                width:100%;
            }
        }
    
  • 循环 类似sass语法 可以使用@for@each循环。@for循环需要一个计数器变量用于追踪循环,通常使用$i。当@for循环时,变量相当于当前循环项而@each 用来循环a list of items instead of numbers。

        @for $i from 1 to 3 {
            p:nth-of-type($i) {   // 在sass语法中 需要用#{} 包裹$i
                margin-left: calc(100%/$i);
            }
    
        }
    
    
        /* after */
    
        p:nth-of-type(1) {
            margin-left: calc( 100% / 1 );
        }
        p:nth-of-type(2) {
            margin-left: calc( 100% / 2 );
        }
        p:nth-of-type(3) {
            margin-left: calc( 100% / 3 );
        }
    
        $list: foo, bar, baz;
    
        @each $icon in ($list) {
            .icon-$(icon) {
                background: url('icons/$(icon).png'); //变量插入string中需要用括号将变量名包裹起来。
            }
        }
    
        /* after */
    
        .icon-foo {
            background: url('icons/foo.png');
        }
    
        .icon-bar {
            background: url('icons/bar.png');
        }
    
        .icon-baz {
            background: url('icons/baz.png');
    }
    
  • mixins precss的混合语法和sass有一些区别。在sass中 定义一个mixin 使用@mixin mixin_name($arg1,$arg2){...}声明,用@include mixin_name(pass_arg1,pass_arg2);来调用声明的混合宏。在precss中,使用@define-mixin mixin-name $arg1, $arg2 {...}声明,用@mixin mixin_name pass_arg1, pass_arg2;来调用。sass 语法使用@content@mixin 能接受额外一整块样式(常见使用场景:媒体查询)。而precss 使用@mixin-content来声明。

        // sass 语法
        //图片容器 定义图片高/宽比例
        @mixin imgratio($width,$size) {
            img{
                width: $width;
                height: 0;
                padding-bottom: $size;
                overflow: hidden;
                @content;
            }
        }
        //图片保持3:2比例
    
        @include imgratio(100%, 66.66%) {
    
            background: red;//@content
        }
    
    
    
        //precss 语法
        @define-mixin imgratio $width, $size {
            img{
                width: $width;
               height: 0;
               padding-bottom: $size;
               overflow: hidden;
            }
    
        }
    
        @mixin imgratio 100%,  66.66% {
            background: red;//@content
        }
    
    
  • extends precss的继承(或扩展)语法和sass有区别。在precss中使用@define-extend extend_name{...}定义继承,用@extend extend_name;调用。而在css中,使用%extend_name{...}来定义继承,使用@extend %extend_name来调用

        //precss
        @defined-extend inline_text_middle {
            display: inline-block;
            vertical-align:middle;
        }
    
        .txt {
            @extend inline_text_middle;
        }
    
    
        //sass
        %inline_text_middle{
            display: inline-block;
            vertical-align: middle;
        }
    
        .txt {
            @extend %inline_text_middle;
        }
  • imports precss导入的语法类似sass

        @import './variables';
        @import './mixins';
        @import './extends';
    

到此precss插件的基本语法就介绍完了。前面介绍过 precss是一个插件包,里面包含了很多插件 具体的可以看官方文档

有的小伙伴可能想了,我不想用这么多包我就单单使用imports。没问题!直接使用postcss-partial-import插件就可以满足你。

还有的小伙伴懒癌晚期,”我好好的sass不用,干嘛要搞一套乱七八糟的插件来实现类似sass语法,烦不烦?”

再次review下postcss的本质,postcss是一个提供了插件系统的工具,不是一个预处理器,所以它不是一个特定的语法拓展,我们可以随心所欲的根据自身的需要使用或者不使用插件。so 我们使用sass的原生语法没问题,你只要使用你想要的插件就可以了(可以参考下文postcss配置)。

PostCSS插件选择

postcss既然有插件系统,选择恐惧症患者现在就纠结了,如此多的插件我该选择哪个呢?难道要上vip.com才能不纠结。。

官方文档对插件就有很多种分类,建议小伙伴们抽空看一下。同时还有一个网站可以查找插件 postcss.parts,可以再这里搜到你想要的插件。
插件系统的强大在于插件种类的广泛,几乎包含了你开发中能想到的方方面面,而不是仅仅局限于之前介绍的pre || postprecessor 概念!
到目前为止,你可能已经明白了postcss是个什么东东。那么在实际开发中我们应该怎么用呢?
鉴于我们的项目目前基本上都是使用ykit,下面重点介绍webpack中的配置。至于gulp等配置,网上到处都是,这里就不赘述了。

Postcss 配置

  • 下面主要是介绍webpack的配置和ykit的配置。
  • 配置中没有使用precss来实现类sass语法, 而是直接使用原生语法,方便熟悉sass语法的懒癌患者。
  • postcss plugin配置了cssnext,autoprefixer,postcss-sorting,postcss-alias, postcss-utilities插件。
关于插plugins的配置

创建postcss.config.js文件

    //postcss.config.js
    module.exports = {
        plugins: [
            require('cssnext'), // 支持实用最新的语法css语法
            require('autoprefixer'), // 处理浏览器前缀
            require('postcss-utilities'), // 封装一些常用的css代码组合
            require('postcss-alias'), // 支持自定义别名
            require('postcss-sorting')// 可以根据规则排序css
        ]
    }

在webapck.config.js中使用postcss-loader,具体见上一步。

关于loader的配置

postcss-loader 设置应该在预处理器loader之前配置,在css-loader或者style-loader之后配置。

    //webpack2
    module.exports = {
        module: {
            rules: [
                {
                    test: /\.scss$/,
                    use: [ 'style-loader', 'css-loader', 'sass-loader', 'postcss-loader' ]
                }
            ]
        }
    }

推荐使用extract-text-webpack-plugin插件在bundle || bundles 中取出css到单独文件

    //webpack2用法
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    ...
    {
        test:/\.scss$/,
        loader: ExtractTextPlugin.extract({
        fallbackLoader: "style-loader",
            loader: [
                "css-loader",
                "postcss-loader",
                "sass-loader"
            ]
        })
    }
    ...
    plugins: [
        new ExtractTextPlugin('[name].css')
    ]


    //webpack1用法
    ExtractTextPlugin.extract(
        'style-loader',
        'css-loader!postcss-loader!sass-loader'
    );
在ykit中的配置

ykit使用插件时默认设置了若干loader。使用postcss-loader的话需要替换loader

这个配置中使用ykit-config-qunar插件。

module.exports = {
    plugins: [{
        name: 'qunar',
        options: {
            eslint: true
        }
    }],
    config: function(options) {
        this.config.module.loaders = this.config.module.loaders.map(function(loader) {
            if (loader.test.test('.scss')) {

                return {
                    test: /\.scss$/,
                    loader: options.ExtractTextPlugin.extract(
                        require.resolve('style-loader'), //require.resolve用于从模块名取到绝对路径
                        require.resolve('css-loader') + '?sourceMap!' + require.resolve('postcss-loader') + '?sourceMap!' + require.resolve('@qnpm/fast-sass-loader-china') + '?sourceMap' 
                        //此处使用sass-loader则报错 'Cannot resolve module 'sass-loader',所以按照qunar插件的用法,继续使用fast-sass-loader-china
                    )
                }
            }
            return loader
        })
        return {
             exports: [
                './scripts/pages/test.js',
                './styles/pages/test.scss'
            ],
            modifyWebpackConfig: function(baseConfig) {
                baseConfig.resolve = baseConfig.resolve || {};
                // 设置别名
                baseConfig.resolve.alias = {
                    common: 'scripts/common',
                    libs: 'scripts/libs',
                    pagesRoot: 'scripts/pages',
                    pagesCommon: 'scripts/pages/common',
                    utils: 'scripts/utils'
                }
                return baseConfig
            },
            sync: {
                host : "192.168.237.75",
                path: "/home/q/www/qunarzz.com/vacation_actpackage_backend"
            }
        }
    },
    hooks: {},
    commands: [],
    server: {
        hot: true, // ykit server --hot
        overlay: true // 在当前打开页面提示打包错误
    }
};

小结

经过以上的介绍,小伙伴们应该能看出postcss的功能还是很强大的。痛点在于一个postcss plugin只是实现一个小的功能或者解决一个小的问题:在配置plugins时需要对它们有一定的认知,还需要花费一些时间来配置你需要的plugins。当然你可以使用类似precss此类的插件包来一建生成你需要的环境。不过只要项目init时候约定好了如何plugins,就可以快捷的移植配置。总体来说还是很值得推广使用哒!
我这里写一个基于sass的插件配置,方便懒癌晚期患者服用。(其实上文已经介绍了)

    //postcss.config.js
    module.exports = {
        plugins: [
            require('cssnext'), // 支持实用最新的语法css语法
            require('autoprefixer'), // 处理浏览器前缀
            require('postcss-utilities'), // 封装一些常用的css代码组合
            require('postcss-alias'), // 支持自定义别名
            require('postcss-sorting')// 可以根据规则排序css
        ]
    }

好处

  • 便于移植,因为使用了sass原生语法,以前的sass项目可以快速移植
  • 使用cssnext实现了向前兼容未来语法(css4)
  • 砍掉sass语法对于浏览器前缀的处理,直接使用autoprefixer插件来实现
  • postcss-utilities封装了一些常用css代码组合,减少mixins || extends定义
  • postcss-alias 定义了一些css别名。极大提升开发时敲代码效率。
  • postcss-sorting 代码规范,可实现约定css属性顺序

坏处

  • 需要知道以上插件是干什么的(懒到此等境界的话,也别玩postcss了)
  • 需要知道以上插件的配置(别名的定义具体是什么,utilities里到底封装了哪些代码块等)
  • 需要了解css4等未来语法
  • 需要对代码规范有追求

推荐插件配置中可以额外添加的插件:stylelint 大家都懂的CSS linter工具

参考链接

postcss deep dive

postcss

postcss-loader

precss

autoprefixer

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值