Ionic 主题与暗色
基于 Ionic 8 · 核于 2026-07
速查
- 机制:主题全靠 CSS 变量(CSS custom properties),运行时可改、无需 Sass
- 9 个应用色:
primary/secondary/tertiary/success/warning/danger/light/medium/dark - 每个色成套 6 变量:
base/-rgb/-contrast/-contrast-rgb/-shade(更深)/-tint(更浅)——改色要成套改,否则组件表现不一致 - 命名前缀:应用色统一
--ion-color-*;另有全局--ion-background-color/--ion-text-color等 - 改 Shadow DOM 内部:优先用组件暴露的 CSS 变量;变量不够时用 CSS Shadow Parts
ion-xxx::part(name)(8.8 起暴露更多 part 与 class) - 暗色 3 palette(从
@ionic/{framework}/css/palettes/导入其一):dark.always.css(永远暗)/dark.system.css(默认推荐,跟随系统)/dark.class.css(手动,.ion-palette-dark类) - 暗色坑:暗色变量按 mode 分设(
:root.ios与:root.md),自定义覆盖需同等或更高特异性选择器;建议加<meta name="color-scheme" content="light dark" /> - 工具:官方 Color Generator 可一键生成整套色板变量
一、主题机制:CSS 变量,不需要 Sass
Ionic 的主题系统建立在标准 CSS 变量之上——不需要 Sass 预处理器,改变量即换肤,运行时也能动态改(用 JS 改 --ion-* 即可)。这与旧 UI 库靠编译期 Sass 变量的做法不同,是 Ionic 换肤灵活的根本原因。
主题文件通常放在 src/theme/variables.css(CLI 模板已生成),在 :root 下声明变量即可全局生效。
二、9 个应用色与成套变量
Ionic 预设 9 个语义应用色:
primary、secondary、tertiary、success、warning、danger、light、medium、dark。
关键坑:每个应用色不是一个变量,而是一组 6 个变量,必须成套定义,否则组件在不同状态(按下、对比文字、阴影)下表现会不一致:
| 变量后缀 | 含义 |
|---|---|
base | 基础色(如 --ion-color-primary) |
-rgb | 基础色的 RGB 三元组(供 rgba() 用透明度) |
-contrast | 该色之上的对比文字色 |
-contrast-rgb | 对比文字色的 RGB 三元组 |
-shade | 更深的变体(用于按下 / 阴影) |
-tint | 更浅的变体(用于高亮) |
/* src/theme/variables.css —— 一个应用色要成套 6 个变量 */
:root {
--ion-color-primary: #3880ff;
--ion-color-primary-rgb: 56, 128, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3171e0; /* 更深,用于按下/阴影 */
--ion-color-primary-tint: #4c8dff; /* 更浅,用于高亮 */
}手动凑这 6 个值容易出错——官方 Color Generator 工具输入一个基础色就能生成整套变量,直接拷进
variables.css即可。
三、全局背景 / 文字变量
除应用色外,还有一批全局变量控制整体基调,最常用的是:
--ion-background-color:App 背景色。--ion-text-color:默认文字色。- 以及步进色
--ion-color-step-*(在背景与文字之间插值出的一系列灰阶,供边框/分隔线等用)。
:root {
--ion-background-color: #ffffff;
--ion-text-color: #000000;
}四、定制 Shadow DOM 内部:CSS 变量优先,Shadow Parts 兜底
多数 ion-* 组件用 Shadow DOM 封装,外部普通选择器穿不进内部。定制内部样式有两条正路,按优先级:
- 首选:组件暴露的 CSS 变量——大量内部尺寸/颜色都开了变量口子,直接设即可。
ion-button {
--background: #6030ff;
--border-radius: 8px;
}- 兜底:CSS Shadow Parts(
::part())——当变量不够时,用组件暴露的part名穿透 Shadow DOM 改内部元素样式:
/* 改 ion-select 内部图标的颜色 */
ion-select::part(icon) {
color: var(--ion-color-primary);
}Ionic 8.8 的方向正是「让定制更灵活」:暴露了更多 CSS class 与 CSS Shadow Parts,并为 Modal / Refresher 等新增事件。具体某组件暴露了哪些 part/变量,查官方
docs/api/<component>的 CSS 章节。
五、暗色模式:3 种预置 palette
Ionic 内置 3 种暗色调色板,从 @ionic/{framework}/css/palettes/(或 @ionic/core/css/palettes/)导入其一即可:
| 文件 | 行为 |
|---|---|
dark.always.css | 永远暗色(无视系统设置) |
dark.system.css | 默认推荐:跟随系统 prefers-color-scheme 自动切换 |
dark.class.css | 手动:给 <html> 加/去 .ion-palette-dark 类才生效(做 App 内开关用) |
// 三选一(示例为 core;框架包把 core 换成 angular/react/vue)
// import '@ionic/core/css/palettes/dark.always.css';
// import '@ionic/core/css/palettes/dark.class.css';
import '@ionic/core/css/palettes/dark.system.css';六、暗色的特异性坑与手动开关
特异性坑:Ionic 的暗色变量是按 mode 分别设定的(:root.ios 与 :root.md)。你要覆盖它们时,自定义选择器必须有同等或更高的特异性(比如也写 :root.ios),否则改不动:
/* 覆盖暗色下的 primary,需匹配 mode 的特异性 */
:root.ios,
:root.md {
--ion-color-primary: #a0b4ff;
}系统 UI 适配:建议在 index.html 加一行,让滚动条等系统 UI 一并跟随明暗:
<meta name="color-scheme" content="light dark" />手动开关(配 dark.class.css,做 App 内主题切换):
// 监听系统偏好 + 切换 .ion-palette-dark 类
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
const toggleDark = (on: boolean) =>
document.documentElement.classList.toggle('ion-palette-dark', on);
toggleDark(prefersDark.matches); // 初始跟随系统
prefersDark.addEventListener('change', (e) => toggleDark(e.matches));