Angular Material 22 のテーマは、styles.scss の mat.theme() 1つで決まります。mat.theme() は色・文字・密度を --mat-sys-* という CSS 変数として出し、各コンポーネントはその変数を読んで表示されます。 色は light-dark() で明暗の両方が入るので、color-scheme: dark を書くだけでダークモードになります。

// src/styles.scss
@use '@angular/material' as mat;

html {
  color-scheme: light;               // dark にするとダークモード。light dark で OS の設定に従う
  @include mat.theme((
    color: (
      primary: mat.$azure-palette,   // 主の色
      tertiary: mat.$blue-palette,   // 3番目の色(アクセント)
    ),
    typography: Roboto,              // 文字
    density: 0,                      // 密度(0〜-5)
  ));
}
変えたいもの 書き方
色(用意された12色) color: mat.$violet-palette など
色(自分のブランドの色) ng generate @angular/material:theme-color で作ったパレット
ダークモード color-scheme: dark(または light dark)
一部の色だけ mat.theme-overrides((primary: #b3261e))
1つの部品の形・色 mat.button-overrides(…)・mat.card-overrides(…) など
文字・密度 typography: (plain-family: …)・density: -3
自分で作った部品 background: var(--mat-sys-primary-container)

確認環境:Angular CLI 22.2.2・@angular/material 22.2.2・@angular/cdk 22.2.2、Sass 1.104.1、Node.js 24.21.0、Linux。ng new したプロジェクトに ng add @angular/material を実行し、この記事の styles.scss で ng build しました。ビルドしたページを Chromium 141(playwright-core で操作)で開き、テーマを切り替えるたびに、ボタン・カードなどの色と大きさを getComputedStyle で読み、スクリーンショットで見た目を確かめています。API の仕様は angular/components の 22.2.x ブランチの「Theming」ガイド・theme-color スキーマの README・@angular/material 22.2.2 の Sass のソースで確かめました(確認日 2026年10月13日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Angular Materialテーマのカスタマイズ|色・フォント・ダークモード」

ng add @angular/material で作られるテーマ

ng add @angular/material --skip-confirmation
✔ Found compatible package version: 22.2.2.
UPDATE package.json (1032 bytes)
UPDATE src/styles.scss (1259 bytes)
UPDATE src/index.html (634 bytes)

src/styles.scss に次の内容が書き込まれました(コメントは省いています)。

@use '@angular/material' as mat;

html {
  height: 100%;
  @include mat.theme(
    (
      color: (
        primary: mat.$azure-palette,
        tertiary: mat.$blue-palette,
      ),
      typography: Roboto,
      density: 0,
    )
  );
}

body {
  color-scheme: light;
  background-color: var(--mat-sys-surface);
  color: var(--mat-sys-on-surface);
  font: var(--mat-sys-body-medium);
  margin: 0;
  height: 100%;
}

index.html には Roboto と Material Symbols の Google Fonts の <link> が足されました。Material の導入とコンポーネントの使い方は、関連記事「Angular Materialの使い方|導入からテーブル・ダイアログまで」で扱っています。

出力される CSS

ビルドした styles.css を見ると、mat.theme() は --mat-sys-* の変数を出していました。色の変数は light-dark(明るいときの色, 暗いときの色) の形です。

--mat-sys-primary: light-dark(#005cbb, #abc7ff);

light-dark() は CSS の関数で、その要素の color-scheme が light なら1つ目、dark なら2つ目の色になります。CSS の light-dark() そのものは、関連記事「CSSダークモード対応の方法|light-dark()のコピペ例つき」で扱っています。

確かめたテーマと結果の一覧

同じページで body のクラスを付け替え、6通りのテーマを測りました。値はすべて Chromium の getComputedStyle で読んだものです。

テーマ 塗りボタンの背景 ページの背景 自作の帯(primary-container)
① 既定(azure) rgb(0, 92, 187) rgb(250, 249, 253) rgb(215, 227, 255)
② 生成した色(brand) rgb(0, 106, 99) rgb(247, 250, 248) rgb(156, 242, 232)
③ 既定+ダーク rgb(171, 199, 255) rgb(18, 19, 22) rgb(0, 69, 143)
④ 生成した色+ダーク rgb(128, 213, 203) rgb(16, 20, 20) rgb(0, 80, 74)
⑤ 上書き(overrides) rgb(179, 38, 30) rgb(250, 249, 253) rgb(255, 218, 214)
⑥ 文字・密度(compact) rgb(0, 92, 187) rgb(250, 249, 253) rgb(215, 227, 255)
テーマ ボタンの角丸 ボタンの高さ 入力欄の高さ カードの角丸
① 既定(文字は Roboto) 9999px 40px 56px 12px
⑤ 上書き(文字は Roboto) 4px 40px 56px 0px
⑥ 文字・密度(文字は serif) 9999px 28px 44px 12px

スクリーンショットでも、①は青、②は緑がかった青(ティール)、③④は暗い背景に明るい色のボタン、⑤は赤いボタンと角の立ったカード、⑥は小さいボタンと明朝体の文字に変わっていました。以下、それぞれの書き方です。

色を変える

用意された12色から選ぶ

Theming ガイドと @angular/material 22.2.2 の Sass では、次の12色のパレットが用意されています。

変数 色 変数 色
mat.$red-palette 赤 mat.$orange-palette オレンジ
mat.$green-palette 緑 mat.$chartreuse-palette 黄緑
mat.$blue-palette 青 mat.$spring-green-palette 青緑
mat.$yellow-palette 黄 mat.$azure-palette 空色(ng add の既定)
mat.$cyan-palette シアン mat.$violet-palette すみれ色
mat.$magenta-palette マゼンタ mat.$rose-palette ばら色

color には、パレットを1つだけ渡す書き方と、primary・tertiary を分けて渡す書き方があります。

@include mat.theme((color: mat.$violet-palette));     // 1つ:主・2番目・3番目の色をこのパレットから

@include mat.theme((
  color: (
    primary: mat.$violet-palette,
    tertiary: mat.$orange-palette,                      // アクセントだけ別の色に
    theme-type: light,                                   // color-scheme(既定)・light・dark
  ),
));

theme-type はガイドによると、color-scheme(既定。light-dark() で両方を出す)・light(明るい色だけ)・dark(暗い色だけ)の3つです。

ブランドの色からパレットを作る(theme-color スキーマ)

ng generate @angular/material:theme-color --primary-color='#0f766e' --tertiary-color='#ea580c' --directory=src/
CREATE src/_theme-colors.scss (2535 bytes)

作られたファイル(137行)の先頭です。

// This file was generated by running 'ng generate @angular/material:theme-color'.
// Proceed with caution if making changes to this file.

@use 'sass:map';
@use '@angular/material' as mat;

// Note: Color palettes are generated from primary: #0f766e, tertiary: #ea580c
$_palettes: (
  primary: (
    0: #000000,
    10: #00201d,
    // …
    40: #006a63,
    // …
    80: #80d5cb,
    // …
    100: #ffffff,
  ),
  secondary: ( … ),
  tertiary: ( … ),
  neutral: ( … ),
  neutral-variant: ( … ),
  error: ( … ),
);
// …
$primary-palette: map.merge(map.get($_palettes, primary), $_rest);
$tertiary-palette: map.merge(map.get($_palettes, tertiary), $_rest);

使うときは、このファイルを @use して mat.theme() に渡します。

@use '@angular/material' as mat;
@use './theme-colors' as brand;

html {
  color-scheme: light;
  @include mat.theme((
    color: (
      primary: brand.$primary-palette,
      tertiary: brand.$tertiary-palette,
    ),
    typography: Roboto,
    density: 0,
  ));
}

指定した #0f766e は、そのままの色では使われませんでした。 塗りボタンの色は、パレットの明るさ40の #006a63(rgb(0, 106, 99))、ダークモードでは明るさ80の #80d5cb でした。Material 3 は、指定した色から明るさの違う16段階(0〜100)の色を作り、文字との対比が取れる段階を使うしくみです(README では「より見やすいよう、十分な対比を持つように最適化される」と説明されています)。ブランドの色をそのまま出したい場所は、後述の theme-overrides で指定します。

theme-color スキーマの主なオプションです(README より)。

オプション 内容
primaryColor 主の色(必須)
secondaryColor・tertiaryColor 2番目・3番目の色。省くと主の色から自動で決まる
neutralColor・neutralVariantColor 背景・枠線などの中間色
errorColor エラーの色
includeHighContrast 高コントラスト用の mixin も作る(既定 false)
directory 出力先のフォルダ
isScss false にすると Sass ではなく CSS 変数のファイルを作る(既定 true)

ダークモード

固定で切り替える・クラスで切り替える

mat.theme() の色は light-dark() なので、color-scheme を変えるだけで切り替わります。 M2 のときのように、暗いテーマを別に作って出し分ける手間がありません。

html {
  color-scheme: light;
  @include mat.theme((color: mat.$azure-palette, typography: Roboto, density: 0));
}

body.dark {
  color-scheme: dark;     // このクラスが付くと暗い色になる
}
// 切り替えボタンの処理(例)
toggleDark(): void {
  document.body.classList.toggle('dark');
}

body に dark を付けると、塗りボタンは rgb(0, 92, 187) → rgb(171, 199, 255)、ページの背景は rgb(250, 249, 253) → rgb(18, 19, 22) に変わりました(上の表の③)。

OS の設定に合わせる

html {
  color-scheme: light dark;   // OS(ブラウザ)の設定に従う
  @include mat.theme((color: mat.$azure-palette, typography: Roboto, density: 0));
}

Playwright で prefers-color-scheme を切り替えて読んだ塗りボタンの色です。

OS の設定(エミュレート) 塗りボタンの背景
light rgb(0, 92, 187)
dark rgb(171, 199, 255)

ガイドには、color-scheme を書かないと常に明るい色になる、とあります。また、Angular Material は prefers-color-scheme などのメディアクエリで自動的にテーマを変えることはしない、とも書かれています。切り替えの方法(OS に合わせる・ボタンで選ぶ・保存した設定を読む)はアプリで決めます。

light-dark() に対応していない版のブラウザも対象にするときは、ガイドのとおり theme-type: light と theme-type: dark のテーマを別々に作り、クラスで出し分けます。

CSS 変数(--mat-sys-*)での上書き

システム変数を上書きする:theme-overrides

body.overrides {
  @include mat.theme-overrides((
    primary: #b3261e,
    primary-container: #ffdad6,
    on-primary-container: #410002,
  ));
}

--mat-sys-primary が #b3261e になり、塗りボタン・チェックボックス・進捗バーなど、主の色を使う部品がまとめて赤になりました(表の⑤)。mat.theme() の第2引数で渡す書き方もあります。

html {
  @include mat.theme((color: mat.$violet-palette, typography: Roboto, density: 0),
    $overrides: (primary-container: orange));
}

この形でコンパイルすると、--mat-sys-primary-container: orange が出力されました。

上書きした色は、ダークモードでも変わりませんでした。 ⑤のまま color-scheme: dark にすると、ページの背景は暗くなりましたが、塗りボタンは rgb(179, 38, 30) のままでした。固定の色で上書きすると、light-dark() が外れるためです。明暗で変えたい場合は、値にも両方を書きます。

@include mat.theme-overrides((
  primary: light-dark(#b3261e, #ffb4ab),
));

この形に直してビルドし直すと、ダークモードの塗りボタンは rgb(255, 180, 171)(#ffb4ab)に変わりました。

上書きに使える主な色の変数です(Theming your components ガイドの一覧から抜き出し)。

変数 主な使われ方
--mat-sys-primary / --mat-sys-on-primary 塗りボタンなどの色 / その上の文字
--mat-sys-primary-container / --mat-sys-on-primary-container 主の色の薄い面 / その上の文字
--mat-sys-secondary・--mat-sys-secondary-container 2番目の色(選択中のチップなど)
--mat-sys-tertiary・--mat-sys-tertiary-container 3番目の色(アクセント)
--mat-sys-error・--mat-sys-error-container エラー
--mat-sys-surface / --mat-sys-on-surface 面(ページ・カード)の色 / 文字
--mat-sys-surface-container(-low・-high など) 一段上の面
--mat-sys-outline / --mat-sys-outline-variant 枠線 / 薄い枠線
--mat-sys-body-medium・--mat-sys-title-large など 文字の形(font に入れる)
--mat-sys-corner-medium・--mat-sys-corner-full など 角丸

theme-overrides に渡すキーは、変数名から --mat-sys- を取った名前です。ガイドでは、overrides の API はキーの綴りを検査するので、変数を直接書くより安全だとされています。

自分で作った部品で使う

// app.scss
.banner {
  background: var(--mat-sys-primary-container);
  color: var(--mat-sys-on-primary-container);
  border: 1px solid var(--mat-sys-outline-variant);
  border-radius: var(--mat-sys-corner-medium);
  font: var(--mat-sys-body-large);
  padding: 12px 16px;
}

この帯は、テーマを変えるたびに Material の部品と一緒に色が変わりました(表の「自作の帯」の列)。ダークモードでも、別の CSS を書かずに暗い色になっています。CSS 変数そのものの使い方は、関連記事「CSS変数(カスタムプロパティ)の使い方|コピペ実例とダークモード切替」で扱っています。

コンポーネント単位の overrides

各コンポーネントには mat.〇〇-overrides という mixin があり、そのコンポーネントのトークン(色・形・文字などの設定値)だけを変えられます。

body.overrides {
  @include mat.button-overrides((
    filled-container-shape: 4px,      // 塗りボタンの角丸
    outlined-container-shape: 4px,    // 枠線ボタンの角丸
  ));
  @include mat.card-overrides((
    outlined-container-shape: 0,      // 枠線カードの角丸
    outlined-outline-color: #b3261e,  // 枠線カードの線の色
  ));
}

ボタンの角丸は 9999px → 4px、カードの角丸は 12px → 0px になりました(表の⑤)。使えるトークンの名前は、material.angular.dev の各コンポーネントのページの「Styling」タブに一覧があります。@angular/material 22.2.2 のソース(_m3-button.scss など)では、トークンは button-filled-container-shape のように部品名が前に付いた名前で定義されていて、overrides のキーはその部品名を除いた部分です。

よく使う mixin 例
mat.button-overrides filled-container-color・filled-container-shape・outlined-outline-color
mat.card-overrides elevated-container-color・outlined-container-shape・title-text-size
mat.form-field-overrides outlined-outline-color・filled-container-color
mat.toolbar-overrides container-background-color・container-text-color
mat.dialog-overrides container-shape・container-color

ガイドでは、コンポーネントの内部の CSS クラス(.mdc-button__label など)を直接上書きすることは強く勧めない、とされています。DOM の構造やクラス名はいつでも変わりうるからです。

一部の範囲だけテーマを変える

mat.theme() は何度でも呼べます。範囲を限ると、その中だけ別の色になります。

.danger-zone {
  @include mat.theme((color: mat.$red-palette));
}

この記事の②(body.brand)も、この書き方で body の中だけ色を差し替えています。

フォントと密度

html {
  @include mat.theme((
    color: mat.$azure-palette,
    typography: (
      plain-family: ('Noto Sans JP', 'Hiragino Sans', sans-serif),  // 本文
      brand-family: ('"M PLUS Rounded 1c"', sans-serif),           // 見出し
      bold-weight: 700,
      medium-weight: 500,
      regular-weight: 400,
    ),
    density: -2,
  ));
}
  • typography にフォント名1つを渡すと全部の文字に、マップを渡すと本文(plain-family)と見出し(brand-family)を分けられます
  • ガイドによると、1つだけ渡したときの太さは、太字 700・中 500・通常 400 です
  • density は 0〜-5。ガイドでは、1段下げるごとに大きさが 4px ずつ小さくなる、とされています。実際に -3 にすると、ボタンの高さは 40px → 28px、入力欄の高さは 56px → 44px で、どちらも 12px(4px × 3段)小さくなりました

数字で始まる単語を含むフォント名は、引用符を二重に

'M PLUS Rounded 1c' のように書いてコンパイルすると、出力の CSS では引用符が外れて --mat-sys-headline-small: 400 1.5rem / 2rem M PLUS Rounded 1c, sans-serif になりました。Chromium の CSS.supports('font-family', …) で確かめると、次のとおりでした。

font-family の値 正しい指定か
Noto Sans JP, sans-serif true
M PLUS Rounded 1c, sans-serif false(1c が数字で始まるため)
"M PLUS Rounded 1c", sans-serif true

'"M PLUS Rounded 1c"' のように、Sass の引用符の中に CSS の引用符を書くと、出力に "M PLUS Rounded 1c" が残りました。 無効な値になると、そのフォントの指定がまるごと使われません。

日本語のフォントの選び方は、関連記事「CSS font-family日本語おすすめ指定|游ゴシック対応コピペ集」で扱っています。

M2(以前の書き方)からの対応表

v18 までの mat.define-light-theme などの書き方(Material 2、M2)と、v19 以降の mat.theme(Material 3、M3)の対応です。

M2 の書き方 v22 の M3 の書き方
mat.define-palette(mat.$indigo-palette) mat.$azure-palette など12色、または theme-color スキーマ
mat.define-light-theme((color: (primary: …, accent: …, warn: …))) mat.theme((color: (primary: …, tertiary: …)))
accent(アクセント色) tertiary(3番目の色)が近い役割
warn(警告色) error パレット(theme-color の errorColor で作る)
mat.define-dark-theme を作り、.dark { @include mat.all-component-colors($dark) } .dark { color-scheme: dark; }
@include mat.core(); 不要(v22 のソースでは中身の無い mixin)
@include mat.all-component-themes($theme) 不要(mat.theme が全部の変数を出す)
mat.define-typography-config($font-family: …) typography: Roboto または typography: (plain-family: …)
mat.get-theme-color($theme, primary) で色を取り出す var(--mat-sys-primary)
mat.typography-hierarchy($theme) の .mat-headline-5 など var(--mat-sys-headline-small) や mat.system-classes() のクラス
部品のスタイルを内部クラスで上書き mat.button-overrides(…) などの overrides

v22 で M2 の書き方をそのまま使うと

v18 の書き方を v22 でコンパイルすると、次のエラーで止まりました。

@use '@angular/material' as mat;
@include mat.core();
$primary: mat.define-palette(mat.$indigo-palette);
Undefined function.
  ╷
3 │ $primary: mat.define-palette(mat.$indigo-palette);

@angular/material 22.2.2 の _index.scss では、M2 の API は m2- を前に付けた名前で公開されています(@forward './core/m2' as m2-*)。次のように書き換えると、v22 でもコンパイルできました(出力 102,081 バイト)。

@use '@angular/material' as mat;

$primary: mat.m2-define-palette(mat.$m2-indigo-palette);
$accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400);
$theme: mat.m2-define-light-theme((
  color: (primary: $primary, accent: $accent),
  typography: mat.m2-define-typography-config(),
  density: 0,
));

html {
  @include mat.all-component-themes($theme);
}

変数は mat.m2-$indigo-palette ではなく mat.$m2-indigo-palette です(前者は expected "(" のエラーになりました)。Theming ガイドでは、mat.define-light-theme などで作ったテーマの説明は v18 のガイドを見るように案内されています。新しく作るテーマは mat.theme で書くと、ガイドの説明と同じ形になります。

よくある質問

Q. 一部のボタンだけ別の色にしたいです。 A. その範囲に mat.theme() を当てる(「一部の範囲だけテーマを変える」)か、範囲を限って mat.button-overrides((filled-container-color: …)) を書きます。どちらも、その要素の中だけ CSS 変数が変わります。

Q. テーマを変えたのに一部の色が変わりません。 A. 自作の CSS で色を直接書いている場所は変わりません。#1976d2 のような値を var(--mat-sys-primary) に置き換えると、テーマと一緒に変わります。theme-overrides で固定の色を入れた場所は、ダークモードでも変わらない点にも注意します(上の⑤の結果)。

Q. 用意済みの CSS テーマ(prebuilt theme)は使えますか。 A. ガイドによると、@angular/material/prebuilt-themes/ に8つあり、M3 は azure-blue.css・rose-red.css・cyan-orange.css・magenta-violet.css の4つです。angular.json の styles に書いて使います。色を変えるなら、この記事の Sass の書き方になります。

Q. ng build で Inlining of fonts failed と出ます。 A. 本番ビルドでは、Google Fonts の CSS をビルド時に取り込む(インライン化する)設定が既定で有効です。ビルドする環境から fonts.googleapis.com に接続できないと、Inlining of fonts failed. … returned status code: 403. で止まりました。angular.json の production の設定を "optimization": { "fonts": false } にすると、同じ環境でもビルドが通りました。

まとめ

  • v22 のテーマは mat.theme() 1つ。色・文字・密度を --mat-sys-* の CSS 変数として出す
  • 色は12色から選ぶか、ng generate @angular/material:theme-color でブランドの色からパレットを作る。指定した色そのものではなく、対比を考えた段階の色が使われた
  • ダークモードは color-scheme: dark だけ。light dark で OS の設定に従った
  • 色だけ変えるなら mat.theme-overrides、部品の形や色なら mat.〇〇-overrides。固定の色で上書きすると、ダークモードでも変わらない
  • density: -3 でボタンと入力欄が 12px 小さくなった。数字で始まる単語を含むフォント名は二重の引用符で
  • M2 の mat.define-* は v22 では Undefined function。m2- を付けると動くが、新しく書くなら mat.theme

参考・出典

確認日はいずれも 2026年10月13日です。

  • Angular Material「Theming」:https://material.angular.dev/guide/theming
  • Angular Material「Theming your components」:https://material.angular.dev/guide/theming-your-components
  • theme-color スキーマの README(angular/components):https://github.com/angular/components/blob/main/src/material/schematics/ng-generate/theme-color/README.md
  • angular/components の Theming ガイドのソース(22.2.x):https://github.com/angular/components/blob/22.2.x/guides/theming.md
  • Angular Material v18「Theming」(M2 の書き方):https://v18.material.angular.dev/guide/theming
  • MDN「light-dark()」:https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark
  • MDN「color-scheme」:https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Angular Materialテーマのカスタマイズ|色・フォント・ダークモード」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?