- Angular
Angular Materialテーマのカスタマイズ|色・フォント・ダークモード
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期連続の黒字決算。