PostCSS in Practice

Andrey Sitnik, Evil Martians

PostCSS in Practice

Andrey Sitnik, Evil Martians

Our Clients

Our Open Source

Part 1 What is PostCSS?

Older Preprocessors

a {
    <%= include clickable %>
    color: <%= $link-color %>;
}

Inside PostCSS

CSS
source map
Parser
Plugin
Plugin
Stringifier
New CSS
new source map

Usage

gulp.task('css', () => {
    let postcss = require('gulp-postcss');
 
    return gulp.src('src/*.css')
        .pipe( postcss([ plugin1, plugin2 ]) )
        .pipe( gulp.desc('build/') );
});

postcss-nested

.block {
    &_title {
        font-size: 200%;
    }
}
.block_title {
    font-size: 200%;
}

W3C Draft postcss-media-minmax

@media (width <= 600px) {

}
@media (max-width: 600px) {

}

Why did we create PostCSS?

To overcome older preprocessors' limits:

1 000 000 downloads per month

PostCSS Users

Part 2 Plugins

Setting up Plugins

postcss([
    require('autoprefixer')({
        browsers: 'last 2 version'
    }),
    require('postcss-cssnext'),
    require('precss')
])

Problem Implicitness

.icon {
    top: center;
}

Solution postcss-use

@use postcss-center;
 
.icon {
    top: center;
}

Rule 1

All plugins with custom syntax should be added via postcss-use

Rule 2

Start by setting up plugin packs

Part 3 Isolation

Rule 3

Use PostCSS to keep code maintainable—not just for syntax sugar

CommonJS

var moment = require('moment');

Components

Problems

  1. Conflicting selectors
  2. Inherited properties

Problem 1 Conflicting Selectors

logo.css

header.css

.name {
    color: black;
}
.name {
    color: gray;
}

Solution 1 postcss-bem

@b Logo {
    @e name {
        color: gray;
    }
}
.Logo-name {
    color: gray
}

All machines must suffer

Solution 2 CSS Modules

.name {
    color: gray;
}
.Logo__name__sVK0p {
    color: gray
}

CSS Modules in JS

import styles from './logo.css';
 
class Logo extends React.Component {
    render() {
        return <div className={ styles.name }>We</div>;
    }
}

What Isolation You Should Use

CSS Modules:

BEM

Problem 2 Inherited Properties

<Header>
    color: white
    <Logo>
        background: white
    </Logo>
</Header>

Problem 3 Third-Party Widgets

* {
    box-sizing: border-box;
}
div {
    margin-top: 10px;
}

Solution postcss-autoreset

.logo {
    color: black;
}
.logo--big {
    width: 200px;
}
.logo {
    all: initial; 
    color: black;
}
.logo--big {
    width: 200px;
}

W3C Draft postcss-initial — IE support

.logo {
    all: initial;
}
.logo {
    color: black;
    background: white;
    box-sizing: content-box;
    line-height: normal;
    text-shadow: none;
    vertical-align: baseline;
    white-space: normal;

The Best Isolation Method

Part 4 Explicit Code

Rule 4

Use PostCSS to get rid of “magic numbers” in CSS

postcss-assets

Image sizes:

.icon {
    width: width('logo.png');
    height: height('logo.png');
    background: inline('logo.png');
}

postcss-property-lookup

Make a reference to another property:

.icon {
    width: 20px;
    height: @width;
}

W3C Draft postcss-custom-media

@custom-media --phones (width <= 700px);
@custom-media --hidpi  (resolution >= 2dppx);
 
@media (--phones) { }
@media (--phones) and (--hidpi) { }

Rule 5

Use PostCSS to hide hacks

autoprefixer

:fullscreen { }
:-webkit-full-screen { }
:-moz-full-screen { }
:-ms-fullscreen { }
:fullscreen { }

postcss-font-magician

body {
    font-family: Alice;
}
@font-face {
    font-family: Alice;
    font-style: normal;
    font-weight: 400;
    src: local("Alice"),
         url("//fonts.gstatic.com/….woff")
             format("woff");
}
body {
    font-family: Alice;
}

postcss-color-rgba-fallback

.popup {
    background:
        rgba(153, 221, 153, 0.8);
}
.popup {
    background: #99dd99; /* IE 8 */
    background:
        rgba(153, 221, 153, 0.8);
}

postcss-svg-fallback

.icon {
    background: url(logo.svg);
    background-size: 20px 20px;
}
.icon {
    background: url(logo.svg);
    background-size: 20px 20px;
}
 
.no-svg.icon {
    background: url(logo-20x20.png);
}

postcss-svg

.icon {
    background: svg('logo.svg', '[fill]: #c00');
}

Part 6 Linters

Rule 6

Use PostCSS to lint CSS, not just to transform it

stylelint

More than 85 rules:

"rules": {
    "indentation":          2,
    "number-leading-zero":  2,
    "color-no-invalid-hex": 2
}

postcss-flexbugs-fixes

IE 11 flexbox issues:

.foo {
    flex: 1;
}
.foo {
    flex: 1 1 0%;
}

doiuse

main.css:13:3: Pointer events not supported by: IE (9,10)

postcss-browser-reporter

Part 7 Dessert

postcss-write-svg

.arrow {
    @svg {
        polygon {
            fill: green;
            points: 50,100 0,0 0,100;
        }
    }
}

RTLCSS

Part 8 Summary

PostCSS is not an Enemy of Sass

Legacy project:

New project:

.pipe( sass() )
.pipe( postcss([
    ...plugins
]) )
.pipe( postcss([
    precss,
    ...plugins
]) )

The Right Way to Use PostCSS

  1. Use postcss-use for plugins with custom syntax
  2. Start by setting up plugin packs
  3. Write isolated components
  4. Get rid of “magic numbers”
  5. Hide hacks
  6. Use linters

Links