ReactとCSSの切っても切れない関係

木内智史之介(シャッチョー)
ミンカさんけっこんしてくださいおねがいします(ズザー
SEGAさん、DIVAの筐体ください(ズザー

React+Reduxを触りだして、正直なところ、最初は「なんて複雑なんだ…こんなの意味あんのか」なんて思うことをありました。

それでもめげずに(仕事なんで当たり前だばか)取り組み続けた結果、 今ではreact+reduxで組み上がる世界のおおよその景色が見えてくるようになってきました。
(それは幻、という可能性もあり笑)

Reactに関して触りだして、仮想DOMという概念に触れ、WEBページの各種要素がComponentとして細切れにされていく姿を眺めていると、 誰もがふと気づくことがあるかと思います。

あれ、これ、cssもComponentにパッケージされるべきじゃないの?

ということです。

たとえばの話

Twitterコンポーネント

たとえばのイメージ

1
2
3
4
5
6
7
8
9
import Twitter from require("twitter");

const SomePage = () => (
  <div>
    <Twitter id="8823scholar" />
  </div>
);

export default SomePage;

わかりやすい例をあげると、この仮想DOMというシステムは、 「Twitterコンポーネント」というものを、Twitter本体からネットを通じてrequireできる未来が、 そう遠くない未来にやってきそうな感じがします。

その場合、当たり前ですが、cssもそのコンポーネント内部にパッケージされるべきだし、 もっと言えば、そのcssの影響はコンポーネント外部に影響を与えないで隠蔽されるべきです。

ここまできて、ようやく「Reactって未来ある!」と素直に思えました。
俄然やる気がわいてきた!

CSS in JS」と言うらしい。

そんなことを考えながらググってみると、やはりみんな考えることは一緒のようで、情報が出てくる出てくる(笑)
なんなら、react+reduxに関してググった中で、一番と言ってもいいくらい多く語られている内容のようです。

いやあ。
みんなcssには苦しめられていたんだなと笑

現段階で一番分かりやすく比較検討されているページが、

Reactと一緒に使う時のCSS in JSのライブラリ選定とか所感とか
by inuscriptさん

になるので、そちらを参照してもらえるといいかもです。

その中で、自分は、「Aphrodite」と「glamor」が気になったので個別に紹介させてもらいます。

Aphrodite

https://github.com/Khan/aphrodite

おそらく、現段階での最有力候補。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React, { Component } from 'react'
import { StyleSheet, css } from 'aphrodite'

const styles = StyleSheet.create({
  red: {
    color: 'red',
  },
  hover: {
    ':hover': {
      backgroundColor: 'black',
    }
  },
  small: {
    '@media (max-width: 600px)': {
      fontSize: '70%',
    }
  },
});

class IndexPage extends Component {
  render() {
    return (
      <div>
        <div className={css(styles.red)}>aaaaa</div>
        <div className={css(styles.hover)}>bbbbb</div>
        <div className={css(styles.hover, styles.red)}>ccccc</div>
        <div className={css(styles.small)}>ddddd</div>
      </div>
    )
  }
}

export default IndexPage

疑似クラスも、メディアタイプも問題なく動作しています。
親のコンポーネントに設定されたcssは、当然ながらその子コンポーネントすべてに影響を与えます。
通常はその挙動でほぼほぼ問題ないはずなんですが、 場合によっては外部からの一切の影響を受けたくない (先ほどのtwitterコンポーネントのような外部ツールなど。まあ、その場合はiframeを使うかw) というケースもあるかと思います。
その場合は、reset用のクラスを用意して、Componentのrootノードに充ててやればいける…はず! (試していない)

glamor

https://github.com/threepointone/glamor

こちらは、如何にシンプルに記述できるかを目標にしていると思われるライブラリ。
全体的に記述量が少ないのが好感度高いです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React, { Component } from 'react'
import { css, hover, media } from 'glamor'

const red = css({
  color: 'red',
})
const hblack = hover({
  backgroundColor: 'black',
})
const small = media('(max-width: 500px)', {
  fontSize: '70%',
})

class IndexPage extends Component {
  render() {
    return (
      <div>
        <div {...red}>aaaaa</div>
        <div {...hblack}>aaaaa</div>
        <div {...css(red, hblack)}>aaaaa</div>
        <div {...small}>aaaaa</div>
      </div>
    )
  }
}

export default IndexPage

glamorはplugin機構がサポートされているのも、いざという時の拡張が期待できてよい。

import 'glamor/reset'

のように、して、reset cssも組み込まれているのも素晴らしい。

どちらもいいと思います! (楽をしたい派の僕としては、glamorかなあ)