【React】CSSでのスタイルの付け方いろいろ

# 環境

- React 17.0.1
- react-scripts 4.0.0

# やりかたいろいろ

モダンなのは、`Styled Components`か`CSS Modules`か。
`CSS Modules`は、スコープが読み込んだファイルに限定される上に、CSSシンタックスハイライトが使える。

| やりかた                                        |CSS in JS|外部ファイル|CSSの全機能使えるか|CSSシンタックスハイライト|おすすめ度|
|:----------------------------------------------|:-------:|:-------:|:--------------:|:----------------:|:------:|
| [CSS Modules](https://github.com/css-modules/css-modules)                   |  No  | Yes  | Yes  | Yes  | ◯    |
| [Styled Components](https://github.com/styled-components/styled-components) | Yes  |  No  | Yes  | Yes  | ◯    |
| インライン・スタイル                                                              | Yes  |  No  |  No  |  No  | △    |
| [Radium](https://github.com/formidablelabs/radium)                          | Yes  |  No  | Yes  |  No  | △    |
| 外部CSSファイル<br>（※CSSのネームスペースがグローバルになる）                            |  No  | Yes  | Yes  | Yes  | ☓    |

> CSS in JS ライブラリとして、[emotion](https://github.com/emotion-js/emotion) がメジャーっぽい。
> https://qiita.com/__sakito__/items/d240840eef7123f62acf

> create-react-app でプロジェクトを作った場合のデフォルトは、CSS Modules。

# [CSS Modules](https://github.com/css-modules/css-modules)

- CSSファイルを`[name].module.css`（e.g. `App.module.css`）という名前にする（中身は通常のCSS）。
- `className`でスタイルを適用する。
- `react-scripts@2.0.0` からは、[デフォルトで使えます](https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/)。

```css:src/App.module.css
.App {
  text-align: center;
  background-color: black;
  color: white;
}

@media(min-width: 500px) {
  .App {
    width: 450px;
  }
}
```

```jsx:src/App.js
import styles from './App.module.css';

 ...

    return(
      // classNameでstyleを適用する
      <div className={styles.App}>
        ...
      </div>

　　　　　　　　  // 別の例
      <div className={styles['form-control']}>

　　　　　　　　　　　　// 動的に style を適用する
　　　　　　　　　　　　<div className={`${styles['form-control']} ${!isValid && styles.invalid}`}>

    );
```

# [Styled Components](https://github.com/styled-components/styled-components)

```
npm install --save styled-components
// or
yarn add styled-components
```

- `styled`をimportする
- `styled.<html-element>`でスタイルを定義する

```jsx:src/App.js
import styled from 'styled-components'

const StyledDiv = styled.div`  // `styled.{html-element}`という形式でスタイルを定義する
  text-align: center;
  background-color: black;
  color: white;

  &:hover {  // & は .div を示す
    background-color: white;
    color: black;
  }

  @media(min-width: 500px) {
    width: 450px;
  }
`;

 ...

    return(
      <StyledDiv>  // 定義したJSXを使う
        ...
      </StyleDiv>
    );
```

## 動的に値を変える場合

```jsx:src/App.js
const StyledDiv = styled.div`
  text-align: center;
  background-color: ${props => props.alt ? 'black' : 'red'};
`;

 ...

    return(
      <StyledDiv alt={this.state.clicked}>  // booleanを返すstateを指定する
        ...
      </StyleDiv>
    );
```

### メリット
- インラインスタイルが使える（= スコープをそのファイルに限定できる）。

### デメリット
- ~~CSSのシンタックスハイライトが使えない~~

# インライン・スタイル
```jsx:src/App.js
  render() {
    const style = {
      textAlign: 'center', // キャメルケースを使う
      backgroundColor: 'black',
      color: 'white'
    };
    
    ...

    return(
      <div style={style}>
        ...
      </div>
    );
```

### メリット
- インラインスタイルが使える（= スコープをそのファイルに限定できる）。
- スタイル（の一部）を JavaScript/TypeScript でプログラマブルに変更できる。
  - 但し、CSS のクラスをプログラマブルに適応することは可能なため、他の方法と比較して大きなメリットではない。 

### デメリット
- 擬似クラス（e.g. `hover`）、疑似エレメント、メディアクエリー、keyframe animation が使えない。
- スタイルをコンポーネント間で簡単に共有できない。

# [Radium](https://github.com/formidablelabs/radium)

```
npm install --save radium
// or 
yarn add radium
```

## pseudo selectorを使う場合

- `Radium`をimportする
- `Radium()`で囲う

```jsx:src/App.js
import Radium from 'radium';  // Radiumをimportする

  render() {
    const style = {
      textAlign: 'center',
      backgroundColor: 'black',
      color: 'white',
      ':hover': {  // psuedo selectorが使えるようになる
        backgroundColor: 'white',
        color: 'black'
      }
    };
    
    // コード内で上書きする場合 
    style[':hover'] = {
      backgroundColor: 'ｂlue',
      color: 'red'
    };
    
    ...

    return(
      <div style={style}>
        ...
      </div>
    );

    ...

export default Radium(App);  // Radium()で囲う
```

## media queriesを使う場合

- 前述の「pseudo selectorを使う場合」の内容に加えて、、、
- `StyleRoot`をimportする
- アプリケーション全体を`StyleRoot`で囲う

```jsx:src/App.js
import Radium, { StyleRoot } from 'radium';  // StyleRootをimportする

  render() {
    const style = {
      textAlign: 'center',
      backgroundColor: 'black',
      color: 'white',
      '@media(min-width: 500px)': {  // media queriesが使えるようになる
        width: '450px'
      }
    };
    
    ...

    return(
      <StyleRoot>  // StyleRootで囲う
        <div style={style}>
          ...
        </div>
      </StyleRoot>
    );

    ...

export default Radium(App);
```

### メリット
- インラインスタイルが使える（= スコープをそのファイルに限定できる）。
- 通常の CSS が使える。

### デメリット
- CSSのシンタックスハイライトが使えない

# 外部CSSファイル
```css:src/App.css
.App {
  text-align: center;
  background-color: black;
  color: white;
}

@media(min-width: 500px) {
  .App {
    width: 450px;
  }
}
```

```jsx:src/App.js
import './App.css';

  ...

    return(
      <div className="App">
        ...
      </div>
    );
```

### メリット
- CSSがそのまま使える。

### デメリット
- グローバルに定義されるので、メンテナンス性が低い。