Andrey Sitnik, Evil Martians
PostCSS Way
The company behind PostCSS and Autoprefixer
Check out our Twitter for the slides
Part 1. The history of PostCSS
Image: Eric Joiner
My first pull request (2010) …
Source: WALL-E
… was ignored for a year
Source: WALL-E
2 years to plan for the revenge
Autoprefixer inside
Parse CSS
Add prefixes
Remove prefixes
Generate new CSS
Common for any CSS tool
Rework for common tasks
Parse CSS
Add prefixes
Remove prefixes
Generate new CSS
Rework
Autoprefixer inital name was Rework Vendors
Evolution
Rework
PostCSS
PostCSS for common tasks
Parse CSS
Add prefixes
Remove prefixes
Generate new CSS & source maps
PostCSS
Revenge was successful
If you have no time, say it to users
PostCSS is an “under the hood” framework
Autoprefixer
PostCSS
RTLCSS
PostCSS
use: [
'autoprefixer-loader',
'rtlcss-loader'
]
PostCSS’s goal: more CSS tools
Problem 1: performance
Parse CSS
Autoprefixer
RTLCSS
Parse CSS
Problem 2: many environments
gulp-autoprefixer grunt-autoprefixer autoprefixer-loader autoprefixer-cli
gulp-rtlcss grunt-rtlcss rtlcss-loader rtlcss-cli
Problem 3: fear
Meme: Drake - Hotline Bling
Add plugin
Add new tool
So PostCSS became a tool
use: [
'autoprefixer-loader',
'rtlcss-loader'
]
use: [
'postcss-loader'
]
// postcss.config.js
module.exports = {
plugins: {
'autoprefixer': {},
'rtlcss': {}
}
}
PostCSS is still hidden as framework in:
CSS Modules
PostCSS
critical
PostCSS
css-loader
PostCSS
CSS Blocks
PostCSS
Part 2. Basic misconceptions
Image: Eric Joiner
PostCSS and Sass are hard to compare
Should I use Sass or PostCSS?
PostCSS vs. Sass
Sass
PostCSS
Polyfills and prefixes
Isolation
Syntax sugar
Linting
Minification
Syntax sugar
Minification
Normalization
Syntax sugar is not really important
Source: Portal
Important thing: isolation
/* BEM */
.block_element { }
/* CSS Modules */
s = require('./style.css')
/* CSS-in-JS */
Title = styled`
color: black;
`
Important thing: preventing errors
.foo {
margin-top: 20px;
width: 100px;
height: 100px;
margin: 0 auto;
}
Stylelint: this overrides the longhand property before it app.css:5:3
Important thing: sharing best practices
Facebook custom Stylelint rules:
-
slow-css-properties
-
filters-with-svg-files
-
use-variables
-
mobile-flexbox
Talk plan
- Project structure
- Normalization
- Isolation
- Linting
Part 3. Project structure
Image: Eric Joiner
Move browsers to Browserslist config
// .postcssrc
{
"plugins": {
"autoprefixer": {
"browsers": [
"last 1 version",
"> 1% in my stats",
"not dead"
]
}
}
}
// .postcssrc
{
"plugins": {
"autoprefixer": { }
}
}
// .browserslistrc
last 1 version
> 1% in my stats
not dead
Or to package.json
{
…
"browserslist": [
"last 1 version",
"> 1% in my stats",
"not dead",
]
}
Feature 1: A single config for all tools
7
Feature 2: A single development convention
— Do we still support IE 11?
— Check Browserslist config
The only recommended way for Autoprefixer
The only recommended way for Babel 7
Create React App
Part 4. Normalization
Image: Eric Joiner
Browser default styles
We need to normalize default styles
Normalize.css supports many old browsers
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
// .browserslistrc
last 1 version
> 1% in my stats
not dead
// app.css
@import-normalize;
Browserslist + Normalize.css
/* last 3 versions */
audio, video {
display: inline-block;
}
img {
border-style: none;
}
/* last 2 versions */
img {
border-style: none;
}
Part 5. Isolation
Image: Eric Joiner
CSS is global
/* article.css */
.title {
color: black;
}
/* popup.css */
.title {
color: red;
}
Selector conflict
Every website should isolate CSS
Render in PHP, Ruby, etc?
BEM
Yes
No
CSS in separated file?
CSS Modules
Yes
No
CSS-in-JS
BEM only for rendering HTML on back-end
- Lower isolation level
- Easy to make mistake
CSS Modules is automatical BEM
decss-loader is sugar for CSS Modules
import { Popup } from './styles.css'
<Popup big={true}>
.Popup {
width: 400px;
}
.Popup-big {
width: 650px;
}
Styled Components syntax for CSS Modules
import { Popup } from './styles.css'
<Popup big={big}>
import s from './styles.css'
<div className={cx(s.popup, big && s.big)}
decss
default
Part 6. Other
Image: Eric Joiner
Linear gradient starts and finishs too “fast”
Source: larsenwork.com/easing-gradients
linear-gradient(white, black)
Source: larsenwork.com/easing-gradients
linear-gradient(white, ease-in-out, black)
Andreas Larsen
Compare
Source: larsenwork.com/easing-gradients
Linear
postcss-easing-gradients
Part 7. Linting
Image: Eric Joiner
Linter finds errors
.foo {
margin-top: 20px;
width: 100px;
height: 100px;
margin: 0 auto;
}
Stylelint: this overrides the longhand property before it app.css:5:3
Comparison
- Prettier: spaces, formatting
- Stylelint: errors
Stylelint — linter for any styles
Stylelint plugins: stylelint-a11y
*:focus {
outline: none;
}
.button:hover {
background: blue;
}
Stylelint: Expected that .button is used together with :focus pseudo-class app.css:4:1
Saves time for team lead
Senior
Junior
Linter
Linters are more kind when talking
Junior
Senior
Fixes
Junior
Linter
Fixes
Stylelint users
Spreading best practices by talk
Know a language
Have 30 minutes
Convinced
Remember
Remember after year
Popular shared configs for linters
eslint-config-airbnb
eslint-config-airbnb
eslint-plugin-react
eslint-plugin-jsx-a11y
Spreading best practices by shared config
Use shared config
Do not disable rule
Part 8. CSS-in-JS
Image: Eric Joiner
Modern CSS-in-JS !== inline styles
const Link = styled.a`
color: blue;
&:hover {
color: green;
}
`
<style>
.css-kjr4ir4i {
color: blue;
}
.css-kjr4ir4i:hover {
color: green;
}
</style>
Everything in a single file
Source: Cristiano Rastelli
Few other good features
- Dynamic values
- Themes
* In simple cases also can be done
by CSS Custom Properties
Stylelint supports CSS-in-JS out-of-box
"scripts": {
"lint:css": "stylelint src/*.js"
}
CSS-in-JS linters could be smarter
const Title = styled.h1`
color: black;
`
export Component = () => (
<Wrap>
<Title></Title>
</Wrap>
}
Tags
CSS
HTML
+
+
Styled Components compiles CSS in browser ☹️
15 kB
gzip, minified
+ parse CSS in browser
css-literal-loader
const Title = styled('h1')`
color: black;
`
require('./index.js.css')
const Title = () => (
<div className="css-vrj45454" />
)
/* index.js.css */
.css-vrj45454 {
color: black;
}
Generates static CSS during deploy
css-literal-loader compatible with PostCSS
rules: [
{
test: /\.js$/,
use: ['css-literal-loader']
},
{
test: /\.css$/,
use: ['postcss-loader']
}
]
css-literal-loader and dynamic values
const Title = styled('h1')`
color: var(--color);
`
<Title style={{ '--color': 'red' }}>
Part 9. Community
Image: Eric Joiner
Linter mentions (by Google)
ESLint
Stylelint
5 M
0,6 M
Custom plugins
ESLint
Stylelint
635
51
CSS community afraids JS
Is it because JS is too complex today?
Source: The Cult of the Complexity
“Software development
is about managing complexity”
2 types of complexity
In structure
In details
Complexity in details
JS APIs in different browsers
Complexity in structure
jQuery
Bad example of structure complexity
React
SSR
Universal polyfills
webpack hacks
Same components for static landing and webapp
Rewrite components for landing
Good example of structure complexity
PostCSS
Autoprefixer
Code without prefixes
CSS vendor prefixes
Even design is going in structure complexity
Design language
Design system
UI kit
Many different buttons
Balance is better in JS than in CSS
JS
CSS
Structure complexity scales better
Structure
time
level
Details
time
Vendor prefixes
Structure
Details
Autoprefixer
Articles and talks
Best practices doesn’t spreading in CSS
Mistakes in test during hiring in Evil Martians
React
CSS
CSS Modules
CSS-in-JS
Only talks and articles do not work
Blaming users: 130 RTs
Spreading best practices by talk
Know a language
Have 30 minutes
Convinced
Remember
Remember after year
Structural complexity to fix the problem: 4 RTs
Spreading best practices by linter
Use shared config
Do not disable rule
JS is very complex too
[] == '' // -> true
[] == 0 // -> true
[''] == '' // -> true
[0] == 0 // -> true
[0] == '' // -> false
[''] == 0 // -> true
Source: github.com/denysdovhan/wtfjs
Language subsets hide complexity in JS
"use strict"
Compilers hide complexity in JS
/* @flow */
[] == ''
^ Cannot compare empty array literal [1] to string [2]
Linters hide complexity in JS
[] == ''
ESLint: 1:3: Expected '===' and instead saw '=='.
Warnings explain newbie mistakes
Scalability of different complexity types
Structure
Details
Part 10. Summary
Image: Eric Joiner
PostCSS way for project
Browserslist config
PostCSS way for project
Browserslist config
postcss-normalize
PostCSS way for project
Browserslist config
postcss-normalize
autoprefixer
PostCSS way for project
Browserslist config
postcss-normalize
autoprefixer
Components isolation
css-literal-loader
BEM
styled-components
Static
themes & dynamic
React
PostCSS way for project
Browserslist config
postcss-normalize
autoprefixer
Components isolation
Small extras
postcss-easing-gradients, postcss-utilities, rtlcss
PostCSS way for project
Browserslist config
postcss-normalize
autoprefixer
Components isolation
Small extras
Stylelint
PostCSS way for project
Browserslist config
postcss-normalize
autoprefixer
Components isolation
Small extras
Stylelint
* Not a word about preprocessor
PostCSS way for community
Shared Stylelint config with best practices
PostCSS way for community
Shared Stylelint config with best practices
Balance complexity in structure and in details
PostCSS way for community
Shared Stylelint config with best practices
Balance complexity in structure and in details
Promote CSS tools
Good candidate for promotion
CSSTree
Source: github.com/postcss/benchmark
CSS parser
3 times faster than PostCSS
Roman Dvornov
Questions?