LoginSignup
119
67

More than 1 year has passed since last update.

MUI (Material-UI) v5 のスタイリング方法

Posted at

2021年9月16日に MUI (Material-UI) v5 が正式にリリースされましたMaterial-UI v4 のリリースが 2019年3月なので、約2年半ぶりのメジャーアップデートです。正式名称が Material-UI から MUI に変更になり、パッケージ名も @material-ui/* から @mui/* になりました。

MUI v5 ではコンポーネントのスタイリングの実装方法や記法が一新し、Material-UI v4 以前までの独特な記法から、Theme UIchakra などで用いられている sx Prop によるスタイリングになりました。
大幅な変更になるので、v4 からの移行コストは大きいですが、新たに MUI を学ぶ人には優しくなった印象です。

MUI v5 のスタイリング方法を v4 の記法と比較しながら紹介していきます。

yarn add @mui/material @emotion/react @emotion/styled

Introducing MUI Core v5.0
https://mui.com/blog/mui-core-v5/

スタイリングの実装方法

MUI v5 では、スタイリングのコアライブラリが JSS から emotion に変わりました。この記事では説明しないので、詳しく知りたい方は Introducing MUI Core v5.0 を参照してください。

さて、v4 では useStyles という自作フックでコンポーネントのスタイリングをしていましたが、この変更によって v5 からはコンポーネントに sx Prop で直接スタイルを書くことができます。

v4 と v5 の記法の違い

Material-UI v4 の記法

makeStyles でスタイル用のフックを作成し、コンポーネント内で className を取得します。

import { makeStyles, createStyles } from '@material-ui/core/styles';

// フックを作成
const useStyles = makeStyles((theme) => createStyles({
  root: {
    color: theme.palette.primary.main,
    padding: theme.spacing(2),
  },
}));

function Hoge() {
  // フックで className を取得
  const classes = useStyles();
  return (
    <div className={classes.root}>
      Hoge
    </div>
  );
}

MUI v5 の記法

sx Prop にスタイルを直接記入します。

import Box from '@mui/material/Box';

function Hoge() {
  return (
    <Box sx={{ color: 'primary.main', p: 2 }}>
      Hoge
    </Box>
  );
}

sx Prop によって記述量がとても少なくなり、初心者にもわかりやすい記法になりました。
color に指定した primary.main は、MUI テーマのパレットを利用する方法です。v5 で新たに導入されたこの記法では、theme を引数に取る関数(後述)を指定しなくても MUI テーマのパレットを利用することができます。

MUI System
https://mui.com/system/basics/

Palette
https://mui.com/system/palette/

sx Prop について

MUI v5 のすべてのコンポーネントは sx Prop でスタイリング可能です。sx Prop は従来の(React では非推奨ですが)style Prop に似ていますが、MUI テーマに基づいたスタイリングや、レスポンシブで動的なスタイリングが容易という特徴があります。

<Box
  sx={{
    width: {
      xs: 100, // theme.breakpoints.up('xs')
      sm: 200, // theme.breakpoints.up('sm')
      md: 300, // theme.breakpoints.up('md')
      lg: 400, // theme.breakpoints.up('lg')
      xl: 500, // theme.breakpoints.up('xl')
    },
    height: (theme) => theme.spacing(10) // => 80px (8px * 10)
  }}
>
  This box has a responsive width.
</Box>

sx Prop では、v4 の makeStyle によるスタイリングと同様に、値にtheme を引数にとった関数を指定することができます。

The sx prop
https://mui.com/system/the-sx-prop/

<Box> コンポーネントについて

<Box> コンポーネントは、sx Prop のプロパティを Prop として直接記述できる基礎的なコンポーネントです。実は v4 時代には既に導入されていましたが、パフォーマンスが低いという難点がありました。リリースノートによると、v5 では大幅にパフォーマンスが改善されたそうです。

import Box from '@mui/material/Box';

// padding: 16px (spacing(8px) * 2)
// background-color: theme.palette.primary.dark
<Box p={2} bgcolor="primary.dark" width={100} height={100}>
  hoge
</Box>

<Box> コンポーネントと <Typography> コンポーネントではこの方法で、 sx Prop を使わずにスタイルを設定することができます。

<Box> Component
https://mui.com/components/box/

Properties
https://mui.com/system/properties/

一般の HTML 要素のスタイリング

<div><span> などの一般の HTML 要素は sx Prop を持ちません。これらをスタイリングするには、<Box> コンポーネント や <Typography> コンポーネントを使い、component Prop で HTML 要素を指定するといいでしょう。

import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';

interface ItemProps {
  children: React.ReactNode;
}

function Item({ children }: ItemProps) {
  return (
    <Typography variant="body2" component="span" sx={{ backgroundColor: 'secondary.light', p: 1 }}>
      {children}
    </Typography>
  );
}

function Hoge() {
  return (
    // py (padding-top, padding-bottom): { xs: 16px, sm: 8px }
    <Box component="nav" sx={{ py: [2, 1] }}>
      <Stack spacing={2} direction={{ xs: 'column', sm: 'row' }}>
        <Item>Top</Item>
        <Item>News</Item>
        <Item>Site Map</Item>
      </Stack>
    </Box>
  );
}

<Box> Component
https://mui.com/components/box/

<Typography> Component
https://mui.com/components/typography/

margin, padding と spacing という単位

MUI にはスタイリングの統一感を出すために、padding や margin に指定するための spacing という単位が存在します。spacing は MUI テーマ で規定されていて、デフォルトでは 8px に設定されています。

sx Prop や <Box> コンポーネントで設定する padding や margin には、spacing が単位として使われています。v4 では makeStyles でフックを作る際に、theme.spacing を使うことで spacing の単位が明示的に使われていましたが、v5 になって spacing という単位が暗黙的に使われるようになったので注意が必要です。

// margin-right: 8px (8px * 1)
<Typography component="span" sx={{ mr: 1 }}></Typography>

// padding-top, paading-bottom: 16px (8px * 2)
<Box py={2}></Box>

また、padding と margin だけは spacing を単位に取りますが、その他のプロパティは基本的に px を単位に取るので混同しないように注意が必要です。また、borderRadius は独自の theme.shape.borderRadius (デフォルトは spacing の半分である 4px)という単位を取るので注意しましょう。

// 正円になる
<Box sx={{
  display: 'flex',
  width: 64, // => 64px
  height: 64, // => 64px
  borderRadius: 8, // => 32px (4px * 8)
}} />

<Box sx={{
  display: 'flex',
  width: (theme) => theme.spacing(8), // 64px
  height: (theme) => theme.spacing(8), // 64px 
  borderRadius: 8, // 32px (4px * 8)
}}>

Spacing
https://mui.com/system/spacing/

感想

v3 以前の withStyles、v4 の makeStyles といった Material-UI 特有の記法は Material-UI 入門者にはやや難解な印象がありました。
v5 では sx Prop で記述する形になったので、初心者にはわかりやすくなったものの、パレットカラーの記法や、padding, margin における spacing の暗黙的な利用など、覚えなくてはいけない事柄は増えた印象です。とはいえ、この辺りはおそらく Theme UITailwind CSS でも同じことでしょう。

MUI v5 のスタイリングの触りの部分だけをざっと説明しました。
この先は公式ドキュメント、特に MUI System の項を熟読することをお勧めします。

参考

119
67
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
119
67