Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PostCSS: Build your own CSS processor

PostCSS: Build your own CSS processor

at NodeFest 2016.

Masaaki Morishita

November 13, 2016
Tweet

More Decks by Masaaki Morishita

Other Decks in Technology

Transcript

  1. PostCSS: Build your own
    CSS processor
    morishi'er @ #nodefest

    View Slide

  2. ࣗݾ঺հ
    .about-me {
    name: Masaaki Morishita;
    twitter: @morishitter_;
    github: morishitter;
    qiita: morishitter;
    specializing-in: CSS;
    member-of: 'PostCSS Team';
    works-at: 'Increments, inc.';
    }

    View Slide

  3. Increments
    We are hiring!
    h"ps:/
    /github.com/increments/job-descrip6ons

    View Slide

  4. Do you use PostCSS?

    View Slide

  5. Agenda
    1. PostCSSͱ͸
    2. PostCSS੡πʔϧͷ঺հ
    3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    4. PostCSSͷAPI

    View Slide

  6. Agenda
    1. PostCSSͱ͸
    2. PostCSS੡πʔϧͷ঺հ
    3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    4. PostCSSͷAPI

    View Slide

  7. PostCSSͱ͸
    • Node੡ͷCSSύʔαʔ
    • CSSπʔϧΛ࡞ΔͨΊͷϑϨʔϜϫʔΫ
    • PostCSS੡πʔϧͷ࣮ߦ
    • by Andrey Sitnik

    View Slide

  8. over 12K stars on GitHub !

    View Slide

  9. 4 million DL / month on npm

    View Slide

  10. PostCSSͱ͸
    • ޿͘࢖ΘΕΔΑ͏ʹͳͬͨ
    • CodePenͰ΋࢖͑Δ
    • Bootstrap v5͸PostCSS੡ʹͳΔ͔΋ʁ
    • ར༻اۀɾαʔϏε
    • Google, Facebook, GitHub, Wikipedia, Qiita, etc...

    View Slide

  11. PostCSSͷॲཧͷྲྀΕ
    • PostCSSࣗମ͸ͨͩͷύʔαʔ
    • ASTΛૢ࡞͢ΔͨΊͷAPIΛఏڙ
    • ϓϥάΠϯ͕ASTΛม׵͢Δ

    View Slide

  12. View Slide

  13. PostCSSͷΑ͏ͳπʔϧ͸ੲ͔Β͋ͬͨ

    View Slide

  14. rework
    reworkcss / rework

    View Slide

  15. Modular CSS preprocessing
    with rework
    by TJ Holowaychuk
    h"p:/
    /tjholowaychuk.tumblr.com/post/
    44267035203/modular-css-preprocessing-with-
    rework

    View Slide

  16. Custom CSS preprocessing
    by Nicolas Gallagher
    h"p:/
    /nicolasgallagher.com/custom-css-
    preprocessing/

    View Slide

  17. rework (in 2013)
    • Node੡ͷCSSύʔαʔ
    • ϓϥάΠϯΞʔΩςΫνϟʔ
    • Andrey͕rework-vendorsͱ͍͏ϓϥάΠϯΛ࡞੒
    • ޙͷAutoprefixer
    • ʢҰํͦͷࠒ morishi:er͸YACPΛ։ൃʣ

    View Slide

  18. rework (in 2013)
    • AutoprefixerΛ࡞Δ্Ͱɺrework͸ػೳෆ଍
    • ౰࣌rework͸ϒϥ΢βϋοΫΛύʔεͰ͖ͳ͔ͬͨ
    • ʢ͋ͱTJʹAutoprefixerΛdisΒΕͨΓ…ʣ
    • AndreyʮΑࣗ͠෼Ͱ࡞Ζ͏ʂʯ

    View Slide

  19. View Slide

  20. PostCSSʢʙ v1ʣ
    • 2013/11/4ʹ࠷ॳͷϦϦʔε
    • "PostCSS is a framework for CSS postprocessors"
    • AutoprefixerͷͨΊʹ࡞ΒΕͨ
    • ͜ͷࠒ͸CoffeeScriptͰॻ͔Εͯͨ

    View Slide

  21. PostCSS (v2 ʙ v4)
    • ϓϥάΠϯ͕େྔʹ࡞ΒΕ͍ͯ͘
    • ݴޠ֦ுͷͨΊͷϓϥάΠϯ΋࡞ΒΕ͍ͯ͘
    • cssnext, PreCSS, AtCSS
    • ʮpostprocessorʯͱ͍͏୯ޠΛ࢖Θͳ͘ͳͬͨ
    • ʢAPI͕͜Ζ͜ΖมΘͬͨ…ʣ

    View Slide

  22. PostCSS v5 (current)
    released on August 20, 2015

    View Slide

  23. PostCSS v5
    • ࠓ·ͰͰҰ൪େ͖͍มߋ
    • Custom Syntaxes
    • ύʔαʔ෦෼ΛΧελϚΠζͰ͖ΔΑ͏ʹʢ͋ͱͰઆ໌ʣ
    • 2016೥ݱࡏɺ޿͘࢖ΘΕΔΑ͏ʹ
    • ʢrework͸׬શʹΦϫίϯʹʣ

    View Slide

  24. 1. PostCSSͱ͸
    • PostCSS͸ϓϥάΠϯΞʔΩςΫνϟʔͳCSSύʔαʔ
    • ASTૢ࡞ͷͨΊͷAPIΛఏڙ
    • ϓϥάΠϯΛॻ͘͜ͱͰCSSʹಠࣗͷॲཧΛ͓͜ͳ͏
    • PostCSSͷྺ࢙
    • PostCSS͸rework͕ݩʹͳ͍ͬͯΔ

    View Slide

  25. Agenda
    1. PostCSSͱ͸
    2. PostCSS੡πʔϧͷ঺հ
    3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    4. PostCSSͷAPI

    View Slide

  26. 2. PostCSS੡πʔϧͷ঺հ
    • Autoprefixer
    • Stylelint
    • CSS Modules

    View Slide

  27. Autoprefixer
    • postcss / autoprefixer
    • ʮCan I Useʯͱ͍͏αΠτͷσʔλΛ
    ݩʹࣗಈͰϕϯμʔϓϦϑΟοΫεΛ
    ෇༩͢Δπʔϧ

    View Slide

  28. /* 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;
    }

    View Slide

  29. 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"
    ] })

    View Slide

  30. ྨࣅπʔϧͱͷύϑΥʔϚϯεൺֱ
    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

    View Slide

  31. Stylelint
    • stylelint / stylelint
    • ϞμϯͳCSSϦϯλʔ
    • ΊͪΌͪ͘ΌΧελϚΠζͰ͖Δ
    • SCSS, Less, CSSͷ৽͍͠ه๏ʹ΋࢖
    ͑Δ

    View Slide

  32. Stylelint
    • ϧʔϧ਺͸໿170ݸ
    • CSSLint: 38, scss-lint: 62, CSSComb: 26
    • શͯͷϧʔϧ͸PostCSSϓϥάΠϯͱ࣮ͯ͠૷
    • ಠࣗϧʔϧ΋࡞ΕΔ

    View Slide

  33. in Facebook
    "Improving CSS quality at
    Facebook and beyond"
    h"ps:/
    /code.facebook.com/posts/
    879890885467584/improving-css-quality-at-
    facebook-and-beyond/

    View Slide

  34. 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,
    ...

    View Slide

  35. ઃఆϑΝΠϧूͱΧελϚΠζ
    • stylelint-config-*
    • standard, suitcss, primer, qiita, etc...
    {
    "extends": "stylelint-config-primer",
    "rules": {
    "selector-max-specificity": "0,6,0"
    }
    }

    View Slide

  36. StylelintͷઃఆϑΝΠϧ
    • ϑΥʔϚοτʹؔ͢Δ΋ͷ͕େ൒
    • color-hex-case
    • length-zero-no-unit
    • declaration-block-semicolon-newline-after
    • block-closing-brace-empty-line-before
    • "ܯࠂ"Ͱ͸ͳ͘ɺࣗಈमਖ਼ͯ͠΄͍͠

    View Slide

  37. Stylefmt
    • morishi(er / stylefmt
    • StylelintͷઃఆϑΝΠϧΛݩʹࣗಈͰ
    ϑΥʔϚοτ
    • શͯͷϧʔϧʹରԠͰ͖ͯ͸͍ͳ͍

    View Slide

  38. stylefmt
    // input
    @mixin clearfix () { &::before,
    &::after{content:" ";display
    : table; } &::after {clear: both;}}
    // output
    @mixin clearfix () {
    &::before,
    &::after {
    content: " ";
    display: table;
    }
    &::after {
    clear: both;
    }
    }

    View Slide

  39. CSS Modules
    • css-modules / css-modules
    • CSSͷϞδϡʔϧԽͷΞϓϩʔνͷ1ͭ
    • άϩʔόϧείʔϓ໰୊Λղܾ͢Δ
    ͨΊͷ΋ͷ

    View Slide

  40. 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 (
    ૹ৴
    );
    }
    h"ps:/
    /speakerdeck.com/vjeux/react-css-in-js

    View Slide

  41. CSS in JSܥπʔϧઓ૪
    • Radium, react-style, styling, etc...
    • CSS ModulesνʔϜʮCSS͸CSSϑΝΠϧʹॻ͖͍ͨʯ

    View Slide

  42. CSS Modules
    • webpackΛ࢖͏͜ͱ͕લఏ
    • css-loader, style-loader, (postcss-loader)
    • σϑΥϧτͰϩʔΧϧείʔϓ
    • ηϨΫλ໊ΛʹϋογϡΛ෇͚ͯিಥΛճආ
    • composes ͰଞͷίϯϙʔωϯτͷελΠϧΛ࠶ར༻
    • ͜ΕΒͷػೳΛPostCSSͰ࣮૷

    View Slide

  43. // SubmitButton.js
    import style from './SubmitButton.css';
    export default class SubmitButton extends React.Component {
    render() {
    return (
    ૹ৴;
    );
    }
    };
    /* SubmitButton.css */
    .button {
    display: inline-block;
    padding: 6px 12px;
    font-size: 14px;
    }
    .default {
    composes: button;
    /* other properties */
    }

    View Slide

  44. PostCSS.parts
    h"p:/
    /postcss.parts

    View Slide

  45. 2. PostCSS੡πʔϧͷ঺հ
    • Autoprefixer
    • ϕϯμʔϓϦϑΟοΫεͷࣗಈ෇༩
    • Stylelint
    • ESLintͷΑ͏ʹΧελϚΠζੑͷߴ͍CSSϦϯλʔ
    • CSS Modules
    • CSSʹϩʔΧϧείʔϓΛ

    View Slide

  46. Agenda
    1. PostCSSͱ͸
    2. PostCSS੡πʔϧͷ঺հ
    3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    4. PostCSSͷAPI

    View Slide

  47. ϓϦϓϩηοαʔͱͯ͠ͷCSS
    • ݴޠ֦ு༻ϓϥάΠϯ
    • cssnext, precss, atcss, etc

    View Slide

  48. cssnext
    • MoOx / postcss-cssnext
    • ະདྷͷCSSͷߏจΛࠓͷϒϥ΢β͕ղ
    ऍͰ͖ΔΑ͏ʹτϥϯεύΠϧ͢Δ
    PostCSSϓϥάΠϯू

    View Slide

  49. Custom Proper,es
    input:
    :root { --fontSize-m: 18px; }
    p { font-size: var(--fontSize-m); }
    output:
    p { font-size: 18px; }

    View Slide

  50. 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 */
    }

    View Slide

  51. Custom selectors
    input:
    @custom-selector :--heading h1, h2, h3;
    article :--heading {
    margin-bottom: 2em;
    }
    output:
    article h1,
    article h2,
    article h3 {
    margin-bottom: 2em;
    }

    View Slide

  52. @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;
    }

    View Slide

  53. @extend
    input:
    .error { color: red; }
    .serious-error {
    @extend .error;
    }
    output:
    .error,
    .serious-error {
    color: red;
    }

    View Slide

  54. ϓϦϓϩηοαʔͱͯ͠PostCSSΛ࢖͏ϝϦοτ
    • ඞཁͳػೳ͚ͩΛબ୒Ͱ͖Δ
    • ΧελϚΠζ͕༰қ
    • ύϑΥʔϚϯε

    View Slide

  55. ඞཁͳػೳ͚ͩΛબ୒
    • ʮSass࢖ͬͯΔ͚Ͳ@importͱม਺͚ͩ͋Ε͹͍͍Θʔʯ
    • ʮmixinͱ͔extend͸؅ཧͰ͖ͳ͍͔Β࢖ͬͯͳ͍ʯ
    • PostCSSͳΒඞཁͳϓϥάΠϯ͚ͩΛ௥ՃͰ͖Δ

    View Slide

  56. ΧελϚΠζ͕༰қ
    • 1ͭ1ͭͷϓϥάΠϯ͸খ͍͞ͷͰίϯτϦϏϡʔτ΋͠΍͍͢
    • ϓϥάΠϯΛॻ͘͜ͱͰಠࣗͷΧελϚΠζ͕Մೳ

    View Slide

  57. ύϑΥʔϚϯε
    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

    View Slide

  58. ϓϦϓϩηοαʔͱͯ͠PostCSSΛ࢖͏ͱ͖ͷ஫ҙ఺
    • cssnext
    • ະདྷͷCSSΛઌऔΓ Ͱ͸ͳ͍
    • ϙϦϑΟϧ Ͱ͸ͳ͍
    • γϯλοΫεͷॻ͖৺஍͸Θ͔Δ
    • PreCSS
    • node-sass࢖͓ʁ

    View Slide

  59. ϓϦϓϩηοαʔͱͯ͠PostCSSΛ࢖͏ͱ͖ͷ஫ҙ఺
    • ϓϥάΠϯΛબΜͰ࢖͏ͱ͍͍
    • ͦͷϓϥάΠϯʹԿ͔͋ͬͨͱ͖͸ͳ͓֮͢ޛ
    • ϓϥάΠϯಉ࢜ʹ΋ґଘؔ܎͕͋Δ
    • ʮpostcss-mixins͸postcss-nestedΑΓઌʹಡΈࠐΈ·͠ΐ
    ͏ʯ

    View Slide

  60. 3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    • cssnext: ະདྷͷߏจΛ࢖͑ΔCSSϓϦϓϩηοαʔ
    • ϝϦοτ
    • ඞཁͳػೳ͚ͩɺΧελϚΠζੑɺύϑΥʔϚϯε
    • ஫ҙ఺
    • cssnext͸ϙϦϑΟϧ͡Όͳ͍
    • ϓϥάΠϯબ୒ͷ೉қ౓͕ߴ͍

    View Slide

  61. Agenda
    1. PostCSSͱ͸
    2. PostCSS੡πʔϧͷ঺հ
    3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    4. PostCSSͷAPI

    View Slide

  62. PostCSSͷAPI
    • ASTͷߏ଄
    • ϓϥάΠϯΛ࡞ΔͨΊͷ͍͔ͭ͘ͷAPIΛ঺հ
    • Custom Syntaxes
    h"p:/
    /api.postcss.org/

    View Slide

  63. ͜͏͍͏ม׵Λ͢ΔϓϥάΠϯΛॻ͍ͯΈΔ
    /* input */
    .foo { font-size: 12px; }
    .bar {
    @ref .foo, font-size;
    color: #333;
    }
    /* expected */
    .foo { font-size: 12px; }
    .bar {
    font-size: 12px;
    color: #333;
    }

    View Slide

  64. 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' } ] }

    View Slide

  65. ASTͷϊʔυ

    View Slide

  66. ASTૢ࡞ͷAPI
    • postcss.plugin()
    • container.walk(Rule|AtRule|Decls)()
    • container.insert(Before|After)()
    • container.remove()

    View Slide

  67. postcss.plugin(name, initializer)
    /*
    * @param {string} name
    * @param {function} initializer
    * @return {Plugin} PostCSS plugin
    */

    View Slide

  68. postcss.plugin(name, initializer)
    module.exports = postcss.plugin('postcss-ref', function (opts) {
    opts = opts || {};
    return function (root) {
    // ASTΛม׵͢Δॲཧ
    };
    });

    View Slide

  69. container.walkAtRule([name], callback)
    /*
    * @param {string|RegExp} [name]
    * @param {childIterator} callback
    * @return {false|undefined}
    */
    • Container: ਌ϊʔυʢࢠϊʔυΛ࣋ͭ͜ͱ͕Ͱ͖ΔʣΛੜ੒
    ͢ΔΫϥε

    View Slide

  70. container.walkAtRule([name], callback)
    module.exports = postcss.plugin('postcss-ref', function (opts) {
    opts = opts || {};
    return function (root) {
    root.walkAtRules('ref', function (atrule) {
    // `@ref`ͷAtRuleϊʔυʹରͯ͠ͷॲཧ
    }
    };
    });

    View Slide

  71. container.walkRule([selector], callback)
    /*
    * @param {string|RegExp} [selector]
    * @param {childIterator} callback
    * @return {false|undefined}
    */

    View Slide

  72. container.walkRule([selector], callback)
    root.walkAtRules('ref', function (atrule) {
    var selector; // = '.foo'
    root.walkRules(selector, function (rule) {
    // .foo ηϨΫλͷRuleϊʔυʹରͯ͠ͷॲཧ
    });
    }

    View Slide

  73. container.walkDecls([prop], callback)
    /*
    * @param {string|RegExp} [prop]
    * @param {childIterator} callback
    * @return {false|undefined}
    */

    View Slide

  74. 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'
    });
    });
    }

    View Slide

  75. container.insertBefore(exist, add)
    /*
    * @param {Node|number} exist
    * @param {Node|object|string|Node[]}
    * @return {Node}
    */

    View Slide

  76. 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
    });
    }
    }

    View Slide

  77. container.remove()
    /*
    * @return {Node}
    */
    root.walkAtRules('ref', function (atrule) {
    if (atrule.parent.type === 'rule') {
    atrule.parent.insertBefore(atrule, {
    prop: newProperty,
    value: newValue
    });
    }
    atrule.remove();
    }

    View Slide

  78. ׬੒
    morishi'er / postcss-ref

    View Slide

  79. Custom Syntaxes
    • PostCSS v5ʙͷػೳ
    • จࣈྻ͔ΒPostCSSͷASTΛ૊ΈཱͯΔϓϩάϥϜ
    • CSSҎ֎ͷߏจͷύʔεՄೳʹ
    • PostCSSͷASTʹ͑͞ม׵Ͱ͖Ε͹طଘͷϓϥάΠϯΛద༻Ͱ͖
    Δ

    View Slide

  80. View Slide

  81. Custom Syntaxes
    • postcss-scss, postcss-less
    • SCSS, Less༻ͷPostCSS Syntaxes
    • PostCSSͰSCSS, LessϑΝΠϧΛCSSʹίϯύΠϧͰ͖ΔΑ͏
    ʹͳΔΘ͚Ͱ͸ͳ͍
    • SCSS, Lessίʔυʹରͯ͠ɺม׵ॲཧΛ͢Δ͜ͱ͕Ͱ͖Δ

    View Slide

  82. Custom Syntaxes
    • postcss-js
    • CSS in JSͷͨΊͷ΋ͷ
    • JSΦϒδΣΫτΛPostCSS ASTʹม׵
    • Radium౳Λ࢖͍ͬͯͯ΋PostCSSͷϓϥάΠϯΛ࢖͑Δ

    View Slide

  83. Custom Syntaxes
    • Φϓγϣϯͷ௥Ճ
    • parser: ύʔαʔͷࢦఆ
    • stringifier: Ξ΢τϓοτͷ࢓ํ
    • syntax: parser + stringifier
    var scss = postcss-scss;
    postcss.process([ plugins]).process(source, { syntax: scss });

    View Slide

  84. 4. PostCSSͷAPI
    • ASTͷߏ଄
    • Root, AtRule, Rule, Declara1on, Comment
    • ASTૢ࡞ͷAPI
    • h8p:/
    /api.postcss.org
    • Custom Syntaxes
    • CSSҎ֎ͷߏจ΋PostCSS ASTʹม׵

    View Slide

  85. Agenda
    1. PostCSSͱ͸
    2. PostCSS੡πʔϧͷ঺հ
    3. ϓϦϓϩηοαʔͱͯ͠ͷPostCSS
    4. PostCSSͷAPI

    View Slide

  86. 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, ...

    View Slide

  87. ղܾ͍ͨ͠໰୊͸͍ͭ΋ಉ͡
    ಓ۩ʹৼΓճ͞ΕΔͳ

    View Slide

  88. PostCSS͸ΤίγεςϜͱͯ͠ྑ͘Ͱ͖͍ͯΔ
    PostCSS is Awesome!

    View Slide

  89. Thanks :D
    @morishi(er_

    View Slide