Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
PostCSS: Build your own CSS processor
Search
Masaaki Morishita
November 13, 2016
Technology
4.8k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PostCSS: Build your own CSS processor
at NodeFest 2016.
Masaaki Morishita
November 13, 2016
More Decks by Masaaki Morishita
See All by Masaaki Morishita
Houdini: Abracadabra CSS
morishitter
1
900
Modern CSS: architecture, future specs and build flow
morishitter
13
2.7k
PostCSS and cssnext
morishitter
11
1.8k
PostCSS 5.0: for Custom CSS Preprocessing
morishitter
10
1.2k
PostCSS for beginners
morishitter
6
1.5k
CSSfmt
morishitter
2
280
Introduction to CSS Architecture
morishitter
3
410
Introduction to PostCSS
morishitter
6
1.8k
Yet Another CSS Preprocessor
morishitter
1
5.6k
Other Decks in Technology
See All in Technology
AI駆動開発、viviONの1年 ── うまくいったこと・いかなかったこと
vivion
0
240
Snowflake Horizon Catalog と Apache Iceberg で作る オープンなデータ基盤
kitagawaz
0
440
The seven pitfalls of AI (revised version)
ufried
0
260
HolmesGPTで始めるSREエージェント入門!プラットフォームの障害調査はAIにお任せ 〜
leveragestech
PRO
0
150
FactoryBotアンチパターン / factory_bot anti-patterns
toshimaru
0
130
HacobuにおけるFDEとは/登壇資料(戸井田 裕貴)
hacobu
PRO
1
780
React Nativeでの OTA Updateって、 どう説明する?
ichiki1023
0
150
FinTech 1-2 : Overview of FinTech
ks91
PRO
0
150
[2026 Oracle Technical Deep Dive] AI時代のアプリケーションを支えるCloud NativeとJava EEモダナイゼーション (2026年9月17日開催)
oracle4engineer
PRO
0
120
個別開発で終わらせない。 現場の課題をプロダクトの強さに変える StockmarkのFDE
ktkrhr
0
580
インバスケット試験対策アプリを 作って見えたAIエージェント構築 ナレッジ2選
shichijoyuhi
1
130
生成AIで高い生産性を求められて、 悩み、乗り越えた話
mot_techtalk
2
130
Featured
See All Featured
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
510
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
The Cult of Friendly URLs
andyhume
79
7k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.1k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
380
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
970
Practical Orchestrator
shlominoach
192
12k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
310
The SEO Collaboration Effect
kristinabergwall1
1
590
How to build a perfect <img>
jonoalderson
1
6.1k
Transcript
PostCSS: Build your own CSS processor morishi'er @ #nodefest
ࣗݾհ .about-me { name: Masaaki Morishita; twitter: @morishitter_; github: morishitter;
qiita: morishitter; specializing-in: CSS; member-of: 'PostCSS Team'; works-at: 'Increments, inc.'; }
Increments We are hiring! h"ps:/ /github.com/increments/job-descrip6ons
Do you use PostCSS?
Agenda 1. PostCSSͱ 2. PostCSSπʔϧͷհ 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS 4. PostCSSͷAPI
Agenda 1. PostCSSͱ 2. PostCSSπʔϧͷհ 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS 4. PostCSSͷAPI
PostCSSͱ • NodeͷCSSύʔαʔ • CSSπʔϧΛ࡞ΔͨΊͷϑϨʔϜϫʔΫ • PostCSSπʔϧͷ࣮ߦ • by Andrey
Sitnik
over 12K stars on GitHub !
4 million DL / month on npm
PostCSSͱ • ͘ΘΕΔΑ͏ʹͳͬͨ • CodePenͰ͑Δ • Bootstrap v5PostCSSʹͳΔ͔ʁ • ར༻اۀɾαʔϏε
• Google, Facebook, GitHub, Wikipedia, Qiita, etc...
PostCSSͷॲཧͷྲྀΕ • PostCSSࣗମͨͩͷύʔαʔ • ASTΛૢ࡞͢ΔͨΊͷAPIΛఏڙ • ϓϥάΠϯ͕ASTΛม͢Δ
None
PostCSSͷΑ͏ͳπʔϧੲ͔Β͋ͬͨ
rework reworkcss / rework
Modular CSS preprocessing with rework by TJ Holowaychuk h"p:/ /tjholowaychuk.tumblr.com/post/
44267035203/modular-css-preprocessing-with- rework
Custom CSS preprocessing by Nicolas Gallagher h"p:/ /nicolasgallagher.com/custom-css- preprocessing/
rework (in 2013) • NodeͷCSSύʔαʔ • ϓϥάΠϯΞʔΩςΫνϟʔ • Andrey͕rework-vendorsͱ͍͏ϓϥάΠϯΛ࡞ •
ޙͷAutoprefixer • ʢҰํͦͷࠒ morishi:erYACPΛ։ൃʣ
rework (in 2013) • AutoprefixerΛ࡞Δ্Ͱɺreworkػೳෆ • ࣌reworkϒϥβϋοΫΛύʔεͰ͖ͳ͔ͬͨ • ʢ͋ͱTJʹAutoprefixerΛdisΒΕͨΓ…ʣ •
AndreyʮΑࣗ͠Ͱ࡞Ζ͏ʂʯ
None
PostCSSʢʙ v1ʣ • 2013/11/4ʹ࠷ॳͷϦϦʔε • "PostCSS is a framework for
CSS postprocessors" • AutoprefixerͷͨΊʹ࡞ΒΕͨ • ͜ͷࠒCoffeeScriptͰॻ͔Εͯͨ
PostCSS (v2 ʙ v4) • ϓϥάΠϯ͕େྔʹ࡞ΒΕ͍ͯ͘ • ݴޠ֦ுͷͨΊͷϓϥάΠϯ࡞ΒΕ͍ͯ͘ • cssnext,
PreCSS, AtCSS • ʮpostprocessorʯͱ͍͏୯ޠΛΘͳ͘ͳͬͨ • ʢAPI͕͜Ζ͜ΖมΘͬͨ…ʣ
PostCSS v5 (current) released on August 20, 2015
PostCSS v5 • ࠓ·ͰͰҰ൪େ͖͍มߋ • Custom Syntaxes • ύʔαʔ෦ΛΧελϚΠζͰ͖ΔΑ͏ʹʢ͋ͱͰઆ໌ʣ •
2016ݱࡏɺ͘ΘΕΔΑ͏ʹ • ʢreworkશʹΦϫίϯʹʣ
1. PostCSSͱ • PostCSSϓϥάΠϯΞʔΩςΫνϟʔͳCSSύʔαʔ • ASTૢ࡞ͷͨΊͷAPIΛఏڙ • ϓϥάΠϯΛॻ͘͜ͱͰCSSʹಠࣗͷॲཧΛ͓͜ͳ͏ • PostCSSͷྺ࢙
• PostCSSrework͕ݩʹͳ͍ͬͯΔ
Agenda 1. PostCSSͱ 2. PostCSSπʔϧͷհ 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS 4. PostCSSͷAPI
2. PostCSSπʔϧͷհ • Autoprefixer • Stylelint • CSS Modules
Autoprefixer • postcss / autoprefixer • ʮCan I Useʯͱ͍͏αΠτͷσʔλΛ ݩʹࣗಈͰϕϯμʔϓϦϑΟοΫεΛ
༩͢Δπʔϧ
/* input */ .example { display: flex; user-select: none; -webkit-border-radius:
3px; border-radius: 3px; } /* output */ .example { display: -ms-flexbox; display: flex; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; border-radius: 3px; }
AutoprefixerͷΦϓγϣϯ • αϙʔτϒϥβࢦఆ (ai / browserslist) autoprefixer({ browsers: [ "ie
>= 11", "last 2 Edge versions", "last 2 Firefox versions", "last 2 Chrome versions", "last 2 Safari versions", "last 2 Opera versions", "last 2 iOS versions", "last 2 ChromeAndroid versions" ] })
ྨࣅπʔϧͱͷύϑΥʔϚϯεൺֱ Autoprefixer: 44 ms Stylecow: 200 ms (4.5 times slower)
nib: 340 ms (7.7 times slower) Compass: 2417 ms (54.9 times slower) h"ps:/ /github.com/postcss/benchmark#prefixers
Stylelint • stylelint / stylelint • ϞμϯͳCSSϦϯλʔ • ΊͪΌͪ͘ΌΧελϚΠζͰ͖Δ •
SCSS, Less, CSSͷ৽͍͠ه๏ʹ ͑Δ
Stylelint • ϧʔϧ170ݸ • CSSLint: 38, scss-lint: 62, CSSComb: 26
• શͯͷϧʔϧPostCSSϓϥάΠϯͱ࣮ͯ͠ • ಠࣗϧʔϧ࡞ΕΔ
in Facebook "Improving CSS quality at Facebook and beyond" h"ps:/
/code.facebook.com/posts/ 879890885467584/improving-css-quality-at- facebook-and-beyond/
StylelintͷઃఆϑΝΠϧ { "rules": { "at-rule-no-vendor-prefix": true, "block-no-empty": true, "color-hex-case": "lower",
"color-hex-length": "short", "color-no-invalid-hex": true, "comment-no-empty": true, "custom-property-no-outside-root": true, "declaration-block-no-duplicate-properties": true, "declaration-block-no-ignored-properties": true, "declaration-block-no-shorthand-property-overrides": true, "declaration-no-important": true, "selector-descendant-combinator-no-non-space": true, "selector-max-empty-lines": 0, "selector-max-specificity": "0,5,0", "selector-no-vendor-prefix": true, ...
ઃఆϑΝΠϧूͱΧελϚΠζ • stylelint-config-* • standard, suitcss, primer, qiita, etc... {
"extends": "stylelint-config-primer", "rules": { "selector-max-specificity": "0,6,0" } }
StylelintͷઃఆϑΝΠϧ • ϑΥʔϚοτʹؔ͢Δͷ͕େ • color-hex-case • length-zero-no-unit • declaration-block-semicolon-newline-after •
block-closing-brace-empty-line-before • "ܯࠂ"Ͱͳ͘ɺࣗಈमਖ਼ͯ͠΄͍͠
Stylefmt • morishi(er / stylefmt • StylelintͷઃఆϑΝΠϧΛݩʹࣗಈͰ ϑΥʔϚοτ • શͯͷϧʔϧʹରԠͰ͖͍ͯͳ͍
stylefmt // input @mixin clearfix () { &::before, &::after{content:" ";display
: table; } &::after {clear: both;}} // output @mixin clearfix () { &::before, &::after { content: " "; display: table; } &::after { clear: both; } }
CSS Modules • css-modules / css-modules • CSSͷϞδϡʔϧԽͷΞϓϩʔνͷ1ͭ • άϩʔόϧείʔϓΛղܾ͢Δ
ͨΊͷͷ
CSS in JS • ʮReact: CSS in JSʯby Christopher Chedeau
render() { const style = { display: 'inline-block', padding: '8px 12px', backgroundColor: '#0099ff', color: '#fff', fontSize: '14px', textAlign: 'center' }; return ( <button style={style}>ૹ৴</button> ); } h"ps:/ /speakerdeck.com/vjeux/react-css-in-js
CSS in JSܥπʔϧઓ૪ • Radium, react-style, styling, etc... • CSS
ModulesνʔϜʮCSSCSSϑΝΠϧʹॻ͖͍ͨʯ
CSS Modules • webpackΛ͏͜ͱ͕લఏ • css-loader, style-loader, (postcss-loader) • σϑΥϧτͰϩʔΧϧείʔϓ
• ηϨΫλ໊ΛʹϋογϡΛ͚ͯিಥΛճආ • composes ͰଞͷίϯϙʔωϯτͷελΠϧΛ࠶ར༻ • ͜ΕΒͷػೳΛPostCSSͰ࣮
// SubmitButton.js import style from './SubmitButton.css'; export default class SubmitButton
extends React.Component { render() { return ( <button className={style.default}>ૹ৴</button>; ); } }; /* SubmitButton.css */ .button { display: inline-block; padding: 6px 12px; font-size: 14px; } .default { composes: button; /* other properties */ }
PostCSS.parts h"p:/ /postcss.parts
2. PostCSSπʔϧͷհ • Autoprefixer • ϕϯμʔϓϦϑΟοΫεͷࣗಈ༩ • Stylelint • ESLintͷΑ͏ʹΧελϚΠζੑͷߴ͍CSSϦϯλʔ
• CSS Modules • CSSʹϩʔΧϧείʔϓΛ
Agenda 1. PostCSSͱ 2. PostCSSπʔϧͷհ 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS 4. PostCSSͷAPI
ϓϦϓϩηοαʔͱͯ͠ͷCSS • ݴޠ֦ு༻ϓϥάΠϯ • cssnext, precss, atcss, etc
cssnext • MoOx / postcss-cssnext • ະདྷͷCSSͷߏจΛࠓͷϒϥβ͕ղ ऍͰ͖ΔΑ͏ʹτϥϯεύΠϧ͢Δ PostCSSϓϥάΠϯू
Custom Proper,es input: :root { --fontSize-m: 18px; } p {
font-size: var(--fontSize-m); } output: p { font-size: 18px; }
Custom media queries input: @custom-media --small-viewport (max-width: 600px); @media (--small-viewport)
{ /* styles for small viewport */ } output: @media (max-width: 600px) { /* styles for small viewport */ }
Custom selectors input: @custom-selector :--heading h1, h2, h3; article :--heading
{ margin-bottom: 2em; } output: article h1, article h2, article h3 { margin-bottom: 2em; }
@apply input: :root { --truncate: { white-space: nowrap; overflow: hidden;
text-overflow: ellipsis; } } p { @apply --truncate; } output: p { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@extend input: .error { color: red; } .serious-error { @extend
.error; } output: .error, .serious-error { color: red; }
ϓϦϓϩηοαʔͱͯ͠PostCSSΛ͏ϝϦοτ • ඞཁͳػೳ͚ͩΛબͰ͖Δ • ΧελϚΠζ͕༰қ • ύϑΥʔϚϯε
ඞཁͳػೳ͚ͩΛબ • ʮSassͬͯΔ͚Ͳ@importͱม͚ͩ͋Ε͍͍Θʔʯ • ʮmixinͱ͔extendཧͰ͖ͳ͍͔Βͬͯͳ͍ʯ • PostCSSͳΒඞཁͳϓϥάΠϯ͚ͩΛՃͰ͖Δ
ΧελϚΠζ͕༰қ • 1ͭ1ͭͷϓϥάΠϯখ͍͞ͷͰίϯτϦϏϡʔτ͍͢͠ • ϓϥάΠϯΛॻ͘͜ͱͰಠࣗͷΧελϚΠζ͕Մೳ
ύϑΥʔϚϯε cssnext: 45 ms PreCSS: 64 ms (1.4 times slower)
node-sass: 65 ms (1.4 times slower) Rework: 83 ms (1.8 times slower) Less: 146 ms (3.2 times slower) Stylus: 219 ms (4.7 times slower) Ruby Sass: 1207 ms (26.2 times slower) h"ps:/ /github.com/postcss/benchmark#preprocessors
ϓϦϓϩηοαʔͱͯ͠PostCSSΛ͏ͱ͖ͷҙ • cssnext • ະདྷͷCSSΛઌऔΓ Ͱͳ͍ • ϙϦϑΟϧ Ͱͳ͍ •
γϯλοΫεͷॻ͖৺Θ͔Δ • PreCSS • node-sass͓ʁ
ϓϦϓϩηοαʔͱͯ͠PostCSSΛ͏ͱ͖ͷҙ • ϓϥάΠϯΛબΜͰ͏ͱ͍͍ • ͦͷϓϥάΠϯʹԿ͔͋ͬͨͱ͖ͳ͓֮͢ޛ • ϓϥάΠϯಉ࢜ʹґଘ͕ؔ͋Δ • ʮpostcss-mixinspostcss-nestedΑΓઌʹಡΈࠐΈ·͠ΐ ͏ʯ
3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS • cssnext: ະདྷͷߏจΛ͑ΔCSSϓϦϓϩηοαʔ • ϝϦοτ • ඞཁͳػೳ͚ͩɺΧελϚΠζੑɺύϑΥʔϚϯε •
ҙ • cssnextϙϦϑΟϧ͡Όͳ͍ • ϓϥάΠϯબͷқ͕ߴ͍
Agenda 1. PostCSSͱ 2. PostCSSπʔϧͷհ 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS 4. PostCSSͷAPI
PostCSSͷAPI • ASTͷߏ • ϓϥάΠϯΛ࡞ΔͨΊͷ͍͔ͭ͘ͷAPIΛհ • Custom Syntaxes h"p:/ /api.postcss.org/
͜͏͍͏มΛ͢ΔϓϥάΠϯΛॻ͍ͯΈΔ /* input */ .foo { font-size: 12px; } .bar
{ @ref .foo, font-size; color: #333; } /* expected */ .foo { font-size: 12px; } .bar { font-size: 12px; color: #333; }
ASTͷϊʔυʢҰ෦ൈਮʣ Root { type: 'root', nodes: [ Rule { type:
'rule', nodes: [ Declaration { type: 'decl', prop: 'font-size', value: '12px' } ], selector: '.foo' }, Rule { type: 'rule', nodes: [ AtRule { type: 'atrule', name: 'ref', params: '.foo, font-size' }, Declaration { type: 'decl', prop: 'color', value: '#333' } ], selector: '.bar' } ] }
ASTͷϊʔυ
ASTૢ࡞ͷAPI • postcss.plugin() • container.walk(Rule|AtRule|Decls)() • container.insert(Before|After)() • container.remove()
postcss.plugin(name, initializer) /* * @param {string} name * @param {function}
initializer * @return {Plugin} PostCSS plugin */
postcss.plugin(name, initializer) module.exports = postcss.plugin('postcss-ref', function (opts) { opts =
opts || {}; return function (root) { // ASTΛม͢Δॲཧ }; });
container.walkAtRule([name], callback) /* * @param {string|RegExp} [name] * @param {childIterator}
callback * @return {false|undefined} */ • Container: ϊʔυʢࢠϊʔυΛ࣋ͭ͜ͱ͕Ͱ͖ΔʣΛੜ ͢ΔΫϥε
container.walkAtRule([name], callback) module.exports = postcss.plugin('postcss-ref', function (opts) { opts =
opts || {}; return function (root) { root.walkAtRules('ref', function (atrule) { // `@ref`ͷAtRuleϊʔυʹରͯ͠ͷॲཧ } }; });
container.walkRule([selector], callback) /* * @param {string|RegExp} [selector] * @param {childIterator}
callback * @return {false|undefined} */
container.walkRule([selector], callback) root.walkAtRules('ref', function (atrule) { var selector; // =
'.foo' root.walkRules(selector, function (rule) { // .foo ηϨΫλͷRuleϊʔυʹରͯ͠ͷॲཧ }); }
container.walkDecls([prop], callback) /* * @param {string|RegExp} [prop] * @param {childIterator}
callback * @return {false|undefined} */
container.walkDecls([prop], callback) root.walkAtRules('ref', function (atrule) { var selector; // =
'.foo' var refedProperty; // = 'font-size' var newValue; root.walkRules(selector, function (rule) { rule.walkDecls(refedProperty, function (decl) { newValue = decl.value; // = '12px' }); }); }
container.insertBefore(exist, add) /* * @param {Node|number} exist * @param {Node|object|string|Node[]}
* @return {Node} */
container.insertBefore(exist, add) root.walkAtRules('ref', function (atrule) { root.walkRules(selector, function (rule) {
// }); if (atrule.parent.type === 'rule') { atrule.parent.insertBefore(atrule, { prop: newProperty, value: newValue }); } }
container.remove() /* * @return {Node} */ root.walkAtRules('ref', function (atrule) {
if (atrule.parent.type === 'rule') { atrule.parent.insertBefore(atrule, { prop: newProperty, value: newValue }); } atrule.remove(); }
morishi'er / postcss-ref
Custom Syntaxes • PostCSS v5ʙͷػೳ • จࣈྻ͔ΒPostCSSͷASTΛΈཱͯΔϓϩάϥϜ • CSSҎ֎ͷߏจͷύʔεՄೳʹ •
PostCSSͷASTʹ͑͞มͰ͖ΕطଘͷϓϥάΠϯΛద༻Ͱ͖ Δ
None
Custom Syntaxes • postcss-scss, postcss-less • SCSS, Less༻ͷPostCSS Syntaxes •
PostCSSͰSCSS, LessϑΝΠϧΛCSSʹίϯύΠϧͰ͖ΔΑ͏ ʹͳΔΘ͚Ͱͳ͍ • SCSS, Lessίʔυʹରͯ͠ɺมॲཧΛ͢Δ͜ͱ͕Ͱ͖Δ
Custom Syntaxes • postcss-js • CSS in JSͷͨΊͷͷ • JSΦϒδΣΫτΛPostCSS
ASTʹม • RadiumΛ͍ͬͯͯPostCSSͷϓϥάΠϯΛ͑Δ
Custom Syntaxes • ΦϓγϣϯͷՃ • parser: ύʔαʔͷࢦఆ • stringifier: Ξτϓοτͷํ
• syntax: parser + stringifier var scss = postcss-scss; postcss.process([ plugins]).process(source, { syntax: scss });
4. PostCSSͷAPI • ASTͷߏ • Root, AtRule, Rule, Declara1on, Comment
• ASTૢ࡞ͷAPI • h8p:/ /api.postcss.org • Custom Syntaxes • CSSҎ֎ͷߏจPostCSS ASTʹม
Agenda 1. PostCSSͱ 2. PostCSSπʔϧͷհ 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS 4. PostCSSͷAPI
CSSपลπʔϧɺΞʔΩςΫνϟʔ • PostCSS, rework • cssnext, PreCSS, Sass, Less, Stylus,
... • Radium, react-style, styled-components, css-modules, ... • Stylelint, SCSS Lint, CSS Lint, CSSComb, Stylefmt, ... • OOCSS, SMACSS, ITCSS, BEM, ECSS, Atomic CSS, ... • Bootstrap, FoundaGon, BASSCSS, Tachyons, ...
ղܾ͍͍ͨͭ͠ಉ͡ ಓ۩ʹৼΓճ͞ΕΔͳ
PostCSSΤίγεςϜͱͯ͠ྑ͘Ͱ͖͍ͯΔ PostCSS is Awesome!
Thanks :D @morishi(er_