sx propの使い方 — MUIのスタイリングとstyle・classNameの違い
この章の目次開く
MUIで「この余白をもう少し広げたい」「この文字だけ赤くしたい」と思ったとき、使うのが sx prop です。MUIのコンポーネントはほぼすべてが sx を受け取ります。
<Box sx={{ mt: 2, p: 3, bgcolor: 'grey.100', borderRadius: 1 }}>
中身
</Box>一見すると独自記法が多くて戸惑いますが、ルールは数えるほどしかありません。この章でまとめて押さえます。
学習者style={{ marginTop: 16 }} じゃダメなの?わざわざ sx を覚える意味がわからない…。
動きはします。ただ、style では書けないことが3つあります。順に見ていきます。
styleやclassNameとの違い
style | className | sx | |
|---|---|---|---|
| 生成されるもの | インラインスタイル | 既存のCSSクラス | クラスを自動生成 |
| テーマの値を使える | 使えない | 使えない | 使える |
:hover などの擬似クラス | 書けない | 書ける | 書ける |
| メディアクエリ | 書けない | 書ける | 書ける |
| MUIのスタイルへの優先度 | 勝つ | 負けることがある | 勝つ |
style は擬似クラスとメディアクエリが書けません。className は書けますが、別ファイルにCSSを用意する必要があるうえ、MUIが生成するスタイルは詳細度が高いため外から書いたクラスが効かないことがあります。
sx はその両方を回避できる、MUI専用の入り口です。
<Button
sx={{
bgcolor: 'primary.main',
'&:hover': { bgcolor: 'primary.dark' },
fontSize: { xs: 14, md: 16 },
}}
>
送信
</Button>擬似クラスもレスポンシブも、このオブジェクトの中で完結します。

数値の意味 — 余白は8px刻み
sx で一番よく誤解されるのが数値です。
<Box sx={{ mt: 2 }} />これは margin-top: 2px ではなく margin-top: 16px になります。MUIのテーマは spacing という基準値を持っており、デフォルトは8px。余白系の数値はこれに掛け算されます。
| 書き方 | 実際の値 |
|---|---|
mt: 1 | 8px |
mt: 2 | 16px |
mt: 0.5 | 4px |
mt: '20px' | 20px(文字列で渡せばそのまま) |
8という数字はMaterial Designの「8dpグリッド」に由来します。ソースにも「Material Designのレイアウトは8dpグリッドに揃えると視覚的に整う」という趣旨のコメントが添えられています。
8倍されるキー、されないキー
すべての数値が8倍されるわけではありません。ここを混同すると事故ります。
| キー | 数値の扱い |
|---|---|
m / mt / p / px などの余白系 | spacingの倍数(8px刻み) |
gap | spacingの倍数(8px刻み) |
width / height | 1以下なら%、1より大きければpx |
fontSize | テーマのtypographyを参照。数値はpx |
学習者width: 1 で100%…。知らずにハマったら絶対に原因わからない…。
先生「数値は意味が変わる、文字列はそのまま」と覚えておくと安全です。迷ったら '16px' のように単位付きの文字列で書けば、変換は一切かかりません。
よく使うショートハンド
sx はCSSプロパティ名をそのまま書けますが、余白と色には短縮形が用意されています。
| ショートハンド | 対応するCSS |
|---|---|
m / mt / mr / mb / ml | margin / margin-top / right / bottom / left |
mx / my | 左右の margin / 上下の margin |
p / pt / pr / pb / pl | padding とその各方向 |
px / py | 左右の padding / 上下の padding |
bgcolor | background-color |
borderRadius | border-radius(こちらもspacingの倍数) |
ショートハンドを使わず marginTop: 2 と書いても同じように動きます。短縮形は好みで選んで構いません。
テーマの値を参照する
色は生の値を書かず、テーマのキーを文字列で指定できます。
<Box sx={{ color: 'primary.main', bgcolor: 'grey.100' }} />primary.main や grey.100 は、テーマの palette を辿るパスです。#1976d2 と直接書くよりこちらが推奨されます。理由は2つあります。
- テーマ側で色を変えれば、参照している箇所すべてが一度に変わる
- ダークモードに対応するとき、色の切り替えをテーマに任せられる
より複雑な参照は関数で書きます。
<Box sx={(theme) => ({ boxShadow: theme.shadows[3] })} />sx はオブジェクトだけでなく、テーマを受け取って返す関数も渡せます。
レスポンシブに書く
値をオブジェクトにすると、ブレークポイントごとの指定になります。
<Box sx={{ width: { xs: 1, md: 0.5 }, p: { xs: 2, md: 4 } }} />画面が狭いときは幅100%・余白16px、md 以上では幅50%・余白32pxという意味です。
デフォルトのブレークポイントは次のとおりです。
| キー | 開始幅 | 想定 |
|---|---|---|
xs | 0px | スマートフォン |
sm | 600px | タブレット |
md | 900px | 小さめのノートPC |
lg | 1200px | デスクトップ |
xl | 1536px | 大きな画面 |
指定した幅以上に適用される、モバイルファーストの考え方です。xs から順に上書きされていきます。詳しい使い分けはレスポンシブ対応の章で扱います。
v9で廃止された書き方
古い記事には、次のような書き方が出てきます。
// v8以前では動いた。v9では動かない
<Box mt={2} p={3} bgcolor="grey.100" />sx を経由せず、propとして直接スタイルを渡す書き方で、system props と呼ばれていました。v9でBox・Typography・Grid・Stack・Linkからsystem propsが削除されました。公式のアップグレードガイドに記載があり、実際に Box の型定義からも該当のpropが消えています。
現在は sx にまとめます。
<Box sx={{ mt: 2, p: 3, bgcolor: 'grey.100' }} />よくあるハマりどころ
余白が想定の8倍になる
mt: 16 と書いて128pxになるパターンです。pxのつもりで数値を書くと8倍されます。mt: 2 か mt: '16px' が正解です。
width: 1 で画面いっぱいになる
前述のとおり、width は1以下を%として扱います。
sx が効かない自作コンポーネント
sx はMUIのコンポーネントが受け取るpropです。自分で作った素の <div> には効きません。自作コンポーネントで sx を使いたい場合は、styled() で作るか、MUIの Box でラップします。
パフォーマンスが気になる
sx は便利ですが、渡すたびにスタイルを計算します。同じスタイルを何十回も繰り返す箇所では、styled() で作った再利用コンポーネントのほうが有利です。使い分けはカスタマイズの4段階で扱います。
ちゃんと使うためのポイント
-
sxはテーマを知っているスタイル指定の入口。擬似クラスもメディアクエリもここに書ける - 余白系の数値はspacing(デフォルト8px)の倍数。
mt: 2は16px width/heightは1以下が%。width: 1は100%- 単位付きの文字列(
'16px')で書けば変換はかからない - 色はテーマのパス(
primary.main)で参照する - v9では
<Box mt={2}>は動かない。sxの中に書く
次の章では、sx を踏まえてBox・Stack・Container・Gridでレイアウトを組む方法を扱います。Gridもv9で書き方が変わった部分です。