React
material-ui

material-uiの見た目を調整する3つの方法

More than 1 year has passed since last update.

概要

  • 普通のやり方で調整 -> style, className
  • 個別に調整 -> withStyles
  • 全体の見た目を調整 -> MuiThemeProvider

環境

  • material-ui v1.0.0-beta.17

(本質ではないけど、rails 5.1.4のwebpackerで動作させています)

最終的なフォルダ構成

https://gyazo.com/e70becf1b424f4588bcbbad056341545

アプリ(調整前)

以下のアプリに対して、「普通のやり方」、「個別に調整」、「全体の見た目を調整」を適用していく。

https://gyazo.com/0b777b8d8cde386ead0e8bf075870706

app/javascript/packs/draft.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import DraftApp from '../containers/draft/DraftApp'

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <DraftApp/>
    ,
    document.getElementById('draftIndexRoot'),
  )
});
app/javascript/containers/draft/DraftApp.jsx
import React from 'react'
import Header from '../common/Header'
import Snackbar from 'material-ui/Snackbar';
import Slide from 'material-ui/transitions/Slide';
import DraftIndex from './DraftIndex';

class DraftApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      snackbarOpen: false,
      snackbarMessage: ''
    }
  }

  handleSnackbar = ({open, message, direction}) => () => {
    this.setState({
      snackbarOpen: open,
      snackbarMessage: message,
      snackbarDirection: direction
    })
  };

  render() {
    return (
      <div>
        <Header/>
        <DraftIndex
          handleSnackbar={this.handleSnackbar}
        />
        <Snackbar
          open={this.state.snackbarOpen}
          onRequestClose={
            this.handleSnackbar({
              open: false,
              message: ''
            })
          }
          message={this.state.snackbarMessage}
          transition={<Slide direction={this.state.direction}/>}
        />
      </div>
    )
  }
}

export default DraftApp

app/javascript/containers/common/Header.jsx
import React from 'react';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';

class Header extends React.Component {
  render() {
    return (
      <div>
        <AppBar position='static'>
          <Toolbar>
            <Typography type='title'>
              テストアプリ
            </Typography>
          </Toolbar>
        </AppBar>
      </div>
    )
  }
}

export default Header
app/javascript/containers/draft/DraftIndex.jsx
import React from 'react'
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';

class DraftIndex extends React.Component {
  render() {
    return (
      <div>
        <Typography type='display1'>スナックバーテスト</Typography>
        <Typography type='body1'>ボタン押すとsnackbarがでてきます</Typography>
        <Button
          raised
          onClick={
            this.props.handleSnackbar({open: true, message: 'スナックバー!', direction: 'down'})
          }
        >
          ボタン
        </Button>
      </div>
    )
  }
}

export default DraftIndex

普通のやり方で調整する場合

styleで指定する場合

タグにstyle={{}}を追加して調整する。
とりあえず簡単に見た目を調整できる。

  • 例 font-sizeの調整 cssのプロパティをキャメルケースで表現して指定する。font-sizeであればfontSize。 プロパティの値は''で囲んで表現する。
style={{fontSize: '4em'}}

実際に適用するとこんな感じ。

https://gyazo.com/36d00d2d597e441bc1bf4045389b8700

app/javascript/containers/draft/DraftIndex.jsx
import React from 'react'
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';

class DraftIndex extends React.Component {
  render() {
    return (
      <div>
        <Typography type='display1'>スナックバーテスト</Typography>
        <Typography type='body1'>ボタン押すとsnackbarがでてきます</Typography>
        <Button
          raised
          onClick={
            this.props.handleSnackbar({open: true, message: 'スナックバー!', direction: 'down'})
          }
          style={{fontSize: '4em'}}
        >
          ボタン
        </Button>
      </div>
    )
  }
}

export default DraftIndex

classNameで指定する場合

classNameにcssが対応するクラス名を指定すると反映される。例えば、bootstrapを導入していれば、bootstrapの独自のクラス名を記述すれば適用される。

<div
  className='btn btn-primary'
>
  class nameで指定
</div>

実際に適用するとこんな感じ。
https://gyazo.com/b3be6828f835aa8e6a11379fb60b9c3c

app/javascript/containers/draft/DraftIndex.jsx
import React from 'react'
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';

class DraftIndex extends React.Component {
  render() {
    return (
      <div>
        <Typography type='display1'>スナックバーテスト</Typography>
        <Typography type='body1'>ボタン押すとsnackbarがでてきます</Typography>
        <Button
          raised
          onClick={
            this.props.handleSnackbar({open: true, message: 'スナックバー!', direction: 'down'})
          }
          style={{fontSize: '4em'}}
        >
          ボタン
        </Button>
        </Button>
        <div
          className='btn btn-primary'
        >
          class nameで指定
        </div>        
      </div>
    )
  }
}

export default DraftIndex

個別に調整するばあい

外部のCSSを使わず、javascriptでCSSを管理するためにに、material-uiで用意されているwithStylesを利用する。

material-uiのコンポーネントの場合、classesを利用することで、スタイルを細かに指定することができる。指定できるプロパティはmaterial-ui/src/ の各コンポーネントのjsファイル内のexport const stylesを参照する。

AppBarコンポーネントの場合、material-ui/src/AppBar/AppBar.jsを見ると、下記の様になっている。

たとえば、colorPrimaryに対して、background-colorとcolorを指定できることがわかる。

material-ui/src/AppBar/AppBar.js
export const styles = (theme: Object) => ({
  root: {
    display: 'flex',
    flexDirection: 'column',
    width: '100%',
    boxSizing: 'border-box', // Prevent padding issue with the Modal and fixed positioned AppBar.
    zIndex: theme.zIndex.appBar,
    flexShrink: 0,
  },
  positionFixed: {
    position: 'fixed',
    top: 0,
    left: 'auto',
    right: 0,
  },
  positionAbsolute: {
    position: 'absolute',
    top: 0,
    left: 'auto',
    right: 0,
  },
  positionStatic: {
    position: 'static',
    flexShrink: 0,
  },
  colorDefault: {
    backgroundColor: theme.palette.background.appBar,
    color: theme.palette.getContrastText(theme.palette.background.appBar),
  },
  colorPrimary: {
    backgroundColor: theme.palette.primary[500],
    color: theme.palette.getContrastText(theme.palette.primary[500]),
  },
  colorAccent: {
    backgroundColor: theme.palette.secondary.A200,
    color: theme.palette.getContrastText(theme.palette.secondary.A200),
  },
});

上記を踏まえて、
1. 見た目を調整したいコンポーネントを選ぶ
2. 上記コンポーネントのうち、material-ui/src/ をみて指定できるmaterial-uiのプロパティを選ぶ
3. styleファイルに固有の名称とともにcssプロパティを記述する
4. コンポーネントを含むclassにwithStylesを追加し、styleファイルを読み込む
5. 変更したいコンポーネントにclassesを追加し、{material-uiのプロパティ: this.props.classes.固有の名称}を付与する

(事例)AppBarの背景色を変更する場合

material-ui/src/AppBar/AppBar.jsを見るとAppBarの背景色はmaterial-uiのプロパティはcolorPrimaryで変更できる事がわかるのでこれを変更する。

styleファイルを作成

下記のフォーマットでオブジェクトを作成する。プロパティとプロパティの値はstyleで指定する場合参照のこと。

スタイル名 = {
    固有の名称: {
      プロパティ: プロパティの値
    }
}

上記を受けて下記の様に作成した。

app/javascript/assets/style.js
export const commonStyle = {
  appBarColorDefault: {
    backgroundColor: '#fff'
  }
};

Header.jsxにclassにwithStylesを追加

styleファイルとwithStylesをimportし、export default withStyles Headerexport default withStyles(commonStyle)(Header)と修正する。

これにより、this.props.classesとしてcommonStyleオブジェクトを使うことができるようになる。

app/javascript/containers/common/Header.jsx
import React from 'react';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';
import {withStyles} from 'material-ui/styles';
import {commonStyle} from '../../assets/style';

class Header extends React.Component {
  render() {
    return (
      <div>
        <AppBar position='static'>
          <Toolbar>
            <Typography type='title'>
              テストアプリ
            </Typography>
          </Toolbar>
        </AppBar>
      </div>
    )
  }
}

export default withStyles(commonStyle)(Header)

Header.jsxの調整したいコンポーネントにclassesを追加する

AppBarにclassesプロパティを追加し、変更したいmaterial-uiのプロパティcolorPrimaryに対してthis.props.classes.appBarColoDefaultを指定する

追加前

<AppBar position='static'>

追加後

<AppBar position='static' classes={{colorPrimary: this.props.classes.appBarColorDefault}}>

このような見た目になる。

https://gyazo.com/ec1da7436130e4a295be4230918db9e6

全体の見た目を調整する場合

アプリ全体の見た目を調整する場合はMuiThemeProviderを使う。
MuitThemProviderで囲んだ箇所から子要素全てに一定のスタイルを適用することができる。

(事例)Typographyを変更する

変更できる箇所は、以下のページを参照のこと。現時点で変更できる箇所と初期値は以下のようにのっているので、そちらを参照して変更する。

https://material-ui-next.com/customization/themes/

{
  "direction": "ltr",
  "palette": {
    "common": {
      "black": "#000",
      "white": "#fff",
      "transparent": "rgba(0, 0, 0, 0)",
      "fullBlack": "rgba(0, 0, 0, 1)",
      "darkBlack": "rgba(0, 0, 0, 0.87)",
      "lightBlack": "rgba(0, 0, 0, 0.54)",
      "minBlack": "rgba(0, 0, 0, 0.26)",
      "faintBlack": "rgba(0, 0, 0, 0.12)",
      "fullWhite": "rgba(255, 255, 255, 1)",
      "darkWhite": "rgba(255, 255, 255, 0.87)",
      "lightWhite": "rgba(255, 255, 255, 0.54)"
    },
以下省略
}

typographyのdipslay1とbody1を変更する場合は下記の様なthemeファイルを作成する。

app/javascript/assets/theme.js
import {createMuiTheme} from 'material-ui/styles';

export const theme = createMuiTheme({
  typography: {
    display1: {
      fontSize: '5em',
      color: 'rgba(255, 0, 0, 1)'
    },
    body1: {
      fontSize: '2em',
      color: 'rgba(0,255,0,1)'
    }
  }
});

上記ファイルを適用する
MuiThemeProviderとthemeをimportし、で囲む。

app/javascript/containers/draft/DraftApp.jsx
import React from 'react'
import Header from '../common/Header'
import Snackbar from 'material-ui/Snackbar';
import Slide from 'material-ui/transitions/Slide';
import DraftIndex from './DraftIndex';
import {MuiThemeProvider} from 'material-ui/styles';
import {theme} from '../../assets/theme';

省略
render() {
    return (
      <MuiThemeProvider theme={theme}>
        <div>
          <Header/>
          <DraftIndex
            handleSnackbar={this.handleSnackbar}
          />
          <Snackbar
            open={this.state.snackbarOpen}
            onRequestClose={
              this.handleSnackbar({
                open: false,
                message: ''
              })
            }
            message={this.state.snackbarMessage}
            transition={<Slide direction={this.state.direction}/>}
          />
        </div>
      </MuiThemeProvider>
    )
  }
}

結果以下のとおり。

https://gyazo.com/d872bf10efff223bc9ee5974dfd6791b

(応用編)themeに用意されていないコンポーネントのスタイルを適用したい場合 -> override

https://material-ui-next.com/customization/themes/ で調整できないコンポーネントの場合は、overridesを使う。

指定はtheme内で行い、指定はoverrides: {Muiコンポーネント名: {}}でおこなう。

下記にSnackbarContentの背景色を変更したい場合を示す。

export const theme = createMuiTheme({
  typography: {
    display1: {
      fontSize: '5em',
      color: 'rgba(255, 0, 0, 1)'
    },
    body1: {
      fontSize: '2em',
      color: 'rgba(0,255,0,1)'
    }
  },
  overrides: {
    MuiSnackbarContent: {
      root: {
        backgroundColor: 'rgba(0,255,255,1)',
      }
    },
  },
});

アプリ(調整後)

結果以下の通りになる。

https://gyazo.com/089e595bf7db517d225fb7dd0756bfda