スタイル

Material UI はスタイルを定義する為の CSS in JS モジュールを提供してます。

インストール

スタイル作成ユーティリティは@material-ui/stylesまたは、@material-ui/core/stylesから取り込めます。取り込む前に以下のどちらか適切な方でそれらをインストールする必要があります。

yarn add @material-ui/style
# または、
yarn add @material-ui/core

使う

スタイルを作成するユーティリティ関数は3つあります。

  1. withStyles
  2. makeStyles
  3. styled

これら3つの中身は正味 JSS で、以下の7つのプラグインを使うインスタンスを使ってます。

  1. jss-plugin-rule-value-function
  2. jss-plugin-global
  3. jss-plugin-nested
  4. jss-plugin-camel-case
  5. jss-plugin-default-unit
  6. jss-plugin-vendor-prefixer
  7. jss-plugin-props-sort

独自のインスタンスを使う

JSS インスタンスを作りStylesProviderコンポーネントに渡すことで、プラグインを追加したり、いらない機能を削除できます。

import {create} from 'jss';
import {
  StylesProvider,
  jssPreset
} from '@material-ui/core/styles';
import rtl from 'jss-rtl';

const jss = create({
  plugins: [
    // 上記の7つのプラグインがほしい場合、
    // コメントアウト
    // ...jssPreset().plugins,
    rtl()
  ]
});

export default () => {
  return (
    <StylesProvider jss={jss}>
      {/* ... */}
    </StylesProvider>
  );
};

withStyles

withStyles はHOC(higher-order component)を作る為のユーティリティです。これは以下のように使います。

const propInjector = withStyles(
  style,
  options
);

styleにはクラスの目印(クラスキー)をプロパティ、 JSS プラグインによって許される様々なスタイルの値をバリューとしたオブジェクト、またはそれを返す関数を置きます。

JSS プラグインによって許される様々なスタイルの値とは以下のような種類があります。
スタイルがオブジェクトなのが一番普通ですが、

const styles = {
  // root はクラスキー
  root: {
    // CSSProperties
    color: 'orange',

    // CreateCSSProperties<Props>
    '&:hover': {
      background: 'blue'
    },
    background: props =>
      props.background
  }
};

スタイルはpropsを引数に渡される関数にもなれます。

const styles = {
  root: props => ({
    color: 'orange',
    '&:hover': {
      background: 'blue'
    },
    background: props.background
  })
};

また、それを返す関数とはテーマオブジェクトを引数に渡さる関数で、その戻り値は上記のstylesのような値になります。

const styles = theme => {
  root: props => ({
    background: props.background
  });
};

このthemeにはThemeProviderなどを使ってテーマオブジェクトを渡すことができます。

withStylesによって得たpropInjectorへコンポーネントを引数として渡して実行することで、そのコンポーネントはclassesオブジェクトをプロパティから扱えます。このオブジェクトはクラスキーとそのクラスキーと対になる実際の HTML クラス名(のグループ)になっているので、

<div className={classes.root}>
  <span className={classes.text}></span>
</div>

のようにクラス名に適切なクラス名が当てられるようにします。

またpropInjectorで得られたコンポーネントはclassesプロパティを渡せるようになります。

const FooWithClasses = propInjector(
  Foo
);

<FooWithClasses classes={/* ... */} />

このclassesプロパティにwithStylesを使う時に定義したものと同じクラスキーとクラス名のオブジェクトを渡すと、Foo内部で受け取るclassesは定義時に作られたものととプロパティとして渡されたものの同じクラスキーのクラス名を組み合わせたものになります。

const classes = {
  root:
    '定義時の`classes.root` プロパティで渡さた`classes.root`'
};

ただしclasseswithStyles使った時に使っていないクラスキーを含めると以下のようなエラーが起こります。

Material-UI: the key `heading` provided to the classes prop is not implemented in App.
You can only override one of the following: root.

makeStyles

makeStylesclassesを返す React カスタムフックを作るためののユーティリティーです。これは、withStylesを作るう時のstyleと同じ値を引数に渡して実行します。

const useStyles = makeStyles(theme => {
  root: props => ({
    background: props.background
  });
});

後はこのuseStylesをコンポーネント内部で実行すればclassesが受け取れます。

const classes = useStyles();
/**
 * classes === {
 *   root: 'makeStyles-root-9',
 * };
 **/

また、このカスタムフックは引数にpropsが渡せ、それをスタイルオブジェクト部分で受け取れます。

styled

styled を使って、styled-components のような感じでスタイル付けすることができます。「のような感じ」というのは、実際には styled-components ではない為です。その為、

styled(Button)`
  color: orange;
`;

のようなタグ付けテンプレートリテラルでスタイルを記述したりはできないようです。