CSS のコンポーネント化ができる CSS Modules というものを知りました。使うと CSS のクラス名をファイルごとに変換してくれます。変換後のクラス名を JavaScript で DOM に割り当てるようです。

React と組み合わせて使ってみました。

インストール

CSS Modules はいくつか使う方法があるみたいです。 Browserify のプラグインもあって、今回はそれを使って見ます。Browserify や Babel プラグイン、 React もインストールしておきます。

$ npm install -g browserify
$ npm install -D babelify css-modulesify
$ npm install -S react react-dom

CSS を JavaScript から読み込む

例として単純なクラスを定義してみます。

/* a.css */

.red {
    color: red;
}

この red というクラスを使うコードが以下です。

// a.js

import React from 'react';
import ReactDOM from 'react-dom';

import styles from './a.css';

class App extends React.Component {
    render() {
        return <div className={styles.red}>Hello, World!</div>;
    }
}

ReactDOM.render(<App />, document.querySelector('#app'));

a.cssimport しているのがポイントです。 styles.red には変換されたクラス名が入っています。 Browserify の変換時にプラグインのオプションを指定します。

$ browserify -o dist/script.js -p [ css-modulesify -o dist/style.css ] -t babelify a.js

css-modulesifydist/style.css にクラス名が変換された CSS を吐き出します。 HTML から dist/script.jsdist/style.css を読みこめば、 Hello, World! という文字が赤く表示されます。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="dist/style.css">
</head>
<body>
    <div id="app"></div>
    <script src="dist/script.js"></script>
</body>
</html>

同じクラス名を使う

これだけだとありがたみがわかりにくいので、同じクラス名を使ってみます。

// a.js

import React from 'react';
import ReactDOM from 'react-dom';

import { B } from './b';
import styles from './a.css';

class App extends React.Component {
    render() {
        return <div className={styles.red}>Hello, <B>World!</B></div>;
    }
}

ReactDOM.render(<App />, document.querySelector('#app'));

<B> というコンポーネントを使っています。その中で red というクラスを使ってみます。

// b.js

import React from 'react';

import styles from './b.css';

export class B extends React.Component {
    render() {
        return <span className={styles.red}>{this.props.children}</span>;
    }
}
/* b.css */

.red {
    color: white;
    background-color: red;
}

これをコンパイルすると、 <App><B> でそれぞれ別のスタイルが適用されます。

まとめ

これまで BEM や SMACSS なんかで CSS のコンポーネント化を頑張っていたと思います。

CSS Modules は JavaScript 側からのアプローチをしていて命名を頑張る必要がなくて、開発者からすると簡単に使えそうです。 Browserify を使っていればビルドのフローに組み込むのもプラグインを指定するだけでできます。

逆にデザイナーと開発者で分業していたりすると使うのは少し難しそうです。