本文へスキップ
ウェブエンジニア問題集
Typography

MUIのTypography — 文字の見た目と意味を分けて指定する

約9分
この章の目次開く

MUIで文字を書くとき、素の <p> や <h2> を置いてもかまいません。ただし Typography を使うと、テーマで決めたフォントサイズや行間が自動で当たります。

このコンポーネントには、他のUIライブラリにあまりない考え方が入っています。「どう見えるか」と「HTMLとして何であるか」を別々のpropで指定するという設計です。

学習者学習者

variant="h4" って書いたら <h4> タグになるんじゃないの?わざわざ2つに分ける意味がわからない…。

既定ではそのとおり <h4> になります。分けられるのは、見た目の大きさと見出しレベルが一致しない場面があるからです。


variantとcomponentの役割

<Typography variant="h4" component="h2">
  セクション見出し
</Typography>
tsx
prop役割
variant見た目のプリセット(フォントサイズ・太さ・行間)
component実際に描画されるHTMLタグ

上の例は「文字の大きさは h4 相当、HTMLとしては <h2>」という指定です。

なぜこれが要るのか。ページ内の2つ目の大見出しは、HTMLの構造上は <h2> であるべきですが、デザイン上は小さめにしたいことがあります。<h4> タグで書いてしまうと、見出しレベルが h1 → h4 と飛び、スクリーンリーダーでの拾い読みがしづらくなります。

見た目のためにタグを選ばない。これがこのpropが存在する理由です。

文章構造を読むイメージ

variantごとに描画されるタグ

component を省略したときに何になるかは、決まった対応表があります。

variant描画されるタグ
h1 〜 h6同じ名前のタグ(<h1> 〜 <h6>)
subtitle1 / subtitle2<h6>
body1 / body2<p>
button / caption / overline<span>

どのタグになるかの決定順

実装では、次の順で最初に見つかったものが使われます。

  1. component prop(指定があれば最優先)
  2. variantMapping prop(そのコンポーネントだけの対応表)
  3. 既定の対応表(上の表)
  4. どれにも当てはまらなければ <span>

button / caption / overline が <span> になるのは、既定の対応表に載っておらず4番目に落ちるためです。


余白は自分で付ける

Typography の既定スタイルには margin: 0 が入っています。ブラウザが <h1> や <p> に付ける余白は消えます。

<Typography variant="h4">見出し</Typography>
<Typography variant="body1">本文がすぐ下に詰まる</Typography>
tsx

意図的な設計です。余白はレイアウト側で決めるという考え方で、Stack の spacing や sx の mb で付けます。

手軽に下余白だけ足したい場合は gutterBottom が使えます。

<Typography variant="h4" gutterBottom>見出し</Typography>
tsx

これで margin-bottom: 0.35em が付きます。文字サイズに比例する相対値なので、見出しが大きいほど余白も広がります。厳密に揃えたいときは sx={{ mb: 2 }} のほうが確実です。


noWrap — はみ出しを省略記号にする

テーブルのセルやカードのタイトルで、長い文字列が折り返して高さを壊すことがあります。

<Typography noWrap>とても長いタイトルがここに入ります</Typography>
tsx

これ1つで、次の3つのCSSがまとめて当たります。

プロパティ値
overflowhidden
text-overflowellipsis
white-spacenowrap

結果として、はみ出した部分が … で省略されます。

先生先生

noWrap が効かない相談のほとんどは、MUIではなくCSSの話です。省略記号は「幅が決まっていること」が前提だと覚えておいてください。


colorとalign

色はテーマのパスを文字列で渡せます。

<Typography color="text.secondary">補足のテキスト</Typography>
<Typography color="error">エラーメッセージ</Typography>
tsx

text.primary / text.secondary のようなパスのほか、primary や error といった役割の名前も受け取ります。生の色コードを書かずテーマ経由にしておくと、ダークモードで自動的に切り替わります。

揃え方は align です。

<Typography align="center">中央寄せ</Typography>
tsx

'inherit'(既定)/ 'left' / 'center' / 'right' / 'justify' から選びます。


プロジェクト全体で対応表を変える

「このアプリでは subtitle1 を常に <p> にしたい」という方針があるなら、テーマにまとめられます。

createTheme({
  components: {
    MuiTypography: {
      defaultProps: {
        variantMapping: {
          subtitle1: 'p',
          subtitle2: 'p',
        },
      },
    },
  },
});
tsx

毎回 component="p" と書く必要がなくなります。カスタマイズの段階としては、カスタマイズの4段階で扱った「全体の方針はテーマに書く」に当たります。


v9で削除されたprop

古い記事には次の書き方が出てきます。

// v8以前。v9では動かない
<Typography paragraph>段落テキスト</Typography>
tsx

paragraph は <p> で描画しつつ下余白を付けるpropでしたが、v9の型定義には存在しません。body1 が既定で <p> になるため、役割が重複していたものと考えられます。

現在はこう書きます。

<Typography variant="body1" gutterBottom>段落テキスト</Typography>
tsx

また3章で触れたとおり、Typography からは system propsも削除されています。<Typography mt={2}> は動かないので、sx に移してください。


よくあるハマりどころ

見出しの下に余白がない

margin: 0 が既定です。gutterBottom か sx で付けます。

subtitle を並べたら見出し構造が壊れた

subtitle1 / subtitle2 は <h6> で描画されます。補足なら component="p" を指定します。

noWrap が効かない

親要素の幅が決まっていません。Flexboxの子なら sx={{ minWidth: 0 }} も併せて確認します。

<Typography mt={2}> が無視される

v9でsystem propsが削除されました。sx={{ mt: 2 }} に書き換えます。

文字サイズをテーマで変えたのに一部だけ変わらない

variant を指定していない Typography は body1 相当になります。変更したのが h1 の設定だけなら、本文には反映されません。


ちゃんと使うためのポイント

  • variant は見た目、component はHTMLタグ。見た目のためにタグを選ばない
  • subtitle1 / subtitle2 は既定で <h6>。補足に使うなら component="p"
  • button / caption / overline は <span>
  • 既定は margin: 0。余白は gutterBottom か sx で付ける
  • noWrap は幅が決まっていて初めて効く
  • 色はテーマのパスで指定するとダークモードに追従する
  • v9では paragraph prop とsystem propsが削除された

次の章では、色やフォントをまとめて管理するテーマの構造を扱います。


参考リンク