Ionic主题定制 #
一、主题概述 #
1.1 Ionic主题系统 #
Ionic的主题系统基于CSS变量,提供灵活的定制能力:
text
主题系统
│
├── 颜色系统
│ ├── 预设颜色
│ ├── 自定义颜色
│ └── 颜色变体
│
├── 全局样式
│ ├── 背景色
│ ├── 文本色
│ └── 字体
│
├── 组件主题
│ ├── 按钮主题
│ ├── 卡片主题
│ └── 列表主题
│
└── 平台主题
├── iOS主题
└── Android主题
1.2 主题文件结构 #
text
src/theme/
├── variables.scss # CSS变量定义
├── common.scss # 通用样式
├── mixins.scss # Sass混入
└── themes/
├── light.scss # 亮色主题
├── dark.scss # 暗黑主题
└── custom.scss # 自定义主题
二、颜色配置 #
2.1 基础颜色配置 #
scss
// src/theme/variables.scss
: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;
// 次要色
--ion-color-secondary: #5260ff;
--ion-color-secondary-rgb: 82, 96, 255;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255, 255, 255;
--ion-color-secondary-shade: #4854e0;
--ion-color-secondary-tint: #636fff;
// 第三色
--ion-color-tertiary: #6a64ff;
--ion-color-tertiary-rgb: 106, 100, 255;
--ion-color-tertiary-contrast: #ffffff;
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
--ion-color-tertiary-shade: #5d58e0;
--ion-color-tertiary-tint: #7974ff;
}
2.2 语义颜色配置 #
scss
:root {
// 成功色
--ion-color-success: #2dd36f;
--ion-color-success-rgb: 45, 211, 111;
--ion-color-success-contrast: #000000;
--ion-color-success-contrast-rgb: 0, 0, 0;
--ion-color-success-shade: #28ba62;
--ion-color-success-tint: #42d77d;
// 警告色
--ion-color-warning: #ffc409;
--ion-color-warning-rgb: 255, 196, 9;
--ion-color-warning-contrast: #000000;
--ion-color-warning-contrast-rgb: 0, 0, 0;
--ion-color-warning-shade: #e0ac08;
--ion-color-warning-tint: #ffca22;
// 危险色
--ion-color-danger: #eb445a;
--ion-color-danger-rgb: 235, 68, 90;
--ion-color-danger-contrast: #ffffff;
--ion-color-danger-contrast-rgb: 255, 255, 255;
--ion-color-danger-shade: #cf3c4f;
--ion-color-danger-tint: #ed576b;
}
2.3 中性颜色配置 #
scss
:root {
// 深色
--ion-color-dark: #222428;
--ion-color-dark-rgb: 34, 36, 40;
--ion-color-dark-contrast: #ffffff;
--ion-color-dark-contrast-rgb: 255, 255, 255;
--ion-color-dark-shade: #1e2023;
--ion-color-dark-tint: #383a3e;
// 中等色
--ion-color-medium: #92949c;
--ion-color-medium-rgb: 146, 148, 156;
--ion-color-medium-contrast: #000000;
--ion-color-medium-contrast-rgb: 0, 0, 0;
--ion-color-medium-shade: #808289;
--ion-color-medium-tint: #9d9fa6;
// 浅色
--ion-color-light: #f4f5f8;
--ion-color-light-rgb: 244, 245, 248;
--ion-color-light-contrast: #000000;
--ion-color-light-contrast-rgb: 0, 0, 0;
--ion-color-light-shade: #d7d8da;
--ion-color-light-tint: #f5f6f9;
}
2.4 自定义品牌颜色 #
scss
// 添加品牌颜色
:root {
// 品牌主色
--ion-color-brand: #ff6b00;
--ion-color-brand-rgb: 255, 107, 0;
--ion-color-brand-contrast: #ffffff;
--ion-color-brand-contrast-rgb: 255, 255, 255;
--ion-color-brand-shade: #e05e00;
--ion-color-brand-tint: #ff7a1a;
}
// 创建颜色类
.ion-color-brand {
--ion-color-base: var(--ion-color-brand);
--ion-color-base-rgb: var(--ion-color-brand-rgb);
--ion-color-contrast: var(--ion-color-brand-contrast);
--ion-color-contrast-rgb: var(--ion-color-brand-contrast-rgb);
--ion-color-shade: var(--ion-color-brand-shade);
--ion-color-tint: var(--ion-color-brand-tint);
}
三、暗黑模式 #
3.1 自动暗黑模式 #
scss
// 跟随系统设置
@media (prefers-color-scheme: dark) {
:root {
// 背景色
--ion-background-color: #121212;
--ion-background-color-rgb: 18, 18, 18;
// 文本色
--ion-text-color: #ffffff;
--ion-text-color-rgb: 255, 255, 255;
// 边框色
--ion-border-color: #333333;
// 列表项背景
--ion-item-background: #1e1e1e;
// 工具栏背景
--ion-toolbar-background: #1f1f1f;
// 标签栏背景
--ion-tab-bar-background: #1f1f1f;
// 卡片背景
--ion-card-background: #1e1e1e;
}
}
3.2 手动暗黑模式 #
typescript
// theme.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ThemeService {
private darkMode = false;
constructor() {
// 从存储中读取主题设置
this.loadTheme();
}
// 切换暗黑模式
toggleDarkMode() {
this.darkMode = !this.darkMode;
this.applyTheme();
this.saveTheme();
}
// 设置暗黑模式
setDarkMode(enabled: boolean) {
this.darkMode = enabled;
this.applyTheme();
this.saveTheme();
}
// 获取当前模式
isDarkMode(): boolean {
return this.darkMode;
}
// 应用主题
private applyTheme() {
document.body.classList.toggle('dark', this.darkMode);
}
// 保存主题设置
private saveTheme() {
localStorage.setItem('darkMode', String(this.darkMode));
}
// 加载主题设置
private loadTheme() {
const saved = localStorage.getItem('darkMode');
if (saved !== null) {
this.darkMode = saved === 'true';
} else {
// 默认跟随系统
this.darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
this.applyTheme();
}
}
scss
// 手动暗黑模式样式
.dark {
--ion-background-color: #121212;
--ion-background-color-rgb: 18, 18, 18;
--ion-text-color: #ffffff;
--ion-text-color-rgb: 255, 255, 255;
--ion-border-color: #333333;
--ion-item-background: #1e1e1e;
--ion-toolbar-background: #1f1f1f;
--ion-tab-bar-background: #1f1f1f;
--ion-card-background: #1e1e1e;
// 调整颜色
--ion-color-primary: #428cff;
--ion-color-primary-rgb: 66, 140, 255;
--ion-color-secondary: #50c8ff;
--ion-color-secondary-rgb: 80, 200, 255;
}
3.3 暗黑模式颜色调整 #
scss
@media (prefers-color-scheme: dark) {
:root {
// 主色调调整
--ion-color-primary: #428cff;
--ion-color-primary-rgb: 66, 140, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3a7be0;
--ion-color-primary-tint: #5598ff;
// 次要色调整
--ion-color-secondary: #50c8ff;
--ion-color-secondary-rgb: 80, 200, 255;
// 成功色调整
--ion-color-success: #2fdf75;
--ion-color-success-rgb: 47, 223, 117;
// 警告色调整
--ion-color-warning: #ffd534;
--ion-color-warning-rgb: 255, 213, 52;
// 危险色调整
--ion-color-danger: #ff4961;
--ion-color-danger-rgb: 255, 73, 97;
// 中性色调整
--ion-color-dark: #f4f5f8;
--ion-color-dark-rgb: 244, 245, 248;
--ion-color-medium: #989aa2;
--ion-color-medium-rgb: 152, 154, 162;
--ion-color-light: #222428;
--ion-color-light-rgb: 34, 36, 40;
}
}
四、平台样式 #
4.1 iOS样式定制 #
scss
// iOS特定样式
.ios {
// 导航栏
ion-toolbar {
--min-height: 44px;
--padding-top: 0;
--padding-bottom: 0;
}
ion-title {
font-size: 17px;
font-weight: 600;
}
// 按钮
ion-button {
--border-radius: 10px;
text-transform: none;
font-weight: 500;
}
// 列表
ion-item {
--padding-start: 16px;
--inner-padding-end: 16px;
}
// 卡片
ion-card {
border-radius: 12px;
margin: 12px;
}
}
4.2 Android样式定制 #
scss
// Android特定样式
.md {
// 导航栏
ion-toolbar {
--min-height: 56px;
--padding-top: 0;
--padding-bottom: 0;
}
ion-title {
font-size: 20px;
font-weight: 500;
}
// 按钮
ion-button {
--border-radius: 4px;
text-transform: uppercase;
font-weight: 500;
letter-spacing: 0.5px;
}
// 列表
ion-item {
--padding-start: 16px;
--inner-padding-end: 16px;
}
// 卡片
ion-card {
border-radius: 4px;
margin: 16px;
}
}
4.3 统一平台样式 #
scss
// 统一iOS和Android样式
:root {
// 统一导航栏高度
ion-toolbar {
--min-height: 56px;
}
// 统一按钮样式
ion-button {
--border-radius: 8px;
text-transform: none;
font-weight: 500;
}
// 统一卡片圆角
ion-card {
border-radius: 12px;
}
}
五、组件主题定制 #
5.1 按钮主题 #
scss
// 主要按钮
ion-button[color="primary"] {
--background: var(--ion-color-primary);
--background-hover: var(--ion-color-primary-shade);
--background-activated: var(--ion-color-primary-shade);
--border-radius: 8px;
--box-shadow: 0 2px 8px rgba(56, 128, 255, 0.3);
font-weight: 600;
letter-spacing: 0.5px;
}
// 轮廓按钮
ion-button[fill="outline"] {
--border-width: 2px;
--border-style: solid;
--border-color: var(--ion-color-primary);
--border-radius: 8px;
}
// 清除按钮
ion-button[fill="clear"] {
--color: var(--ion-color-primary);
--color-hover: var(--ion-color-primary-shade);
}
// 圆形按钮
ion-button[shape="round"] {
--border-radius: 50px;
}
// 大按钮
ion-button[size="large"] {
--padding-top: 16px;
--padding-bottom: 16px;
--padding-start: 24px;
--padding-end: 24px;
font-size: 18px;
}
5.2 卡片主题 #
scss
ion-card {
--background: var(--ion-card-background, #ffffff);
margin: 16px;
border-radius: 16px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
overflow: hidden;
// 悬停效果
&:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
transform: translateY(-2px);
transition: all 0.3s ease;
}
}
ion-card-header {
padding: 16px 16px 8px;
ion-card-title {
font-size: 20px;
font-weight: 700;
color: var(--ion-text-color);
margin-bottom: 4px;
}
ion-card-subtitle {
font-size: 14px;
color: var(--ion-color-medium);
}
}
ion-card-content {
padding: 8px 16px 16px;
font-size: 14px;
line-height: 1.5;
color: var(--ion-text-color);
}
5.3 列表主题 #
scss
ion-list {
background: transparent;
padding: 0;
}
ion-item {
--background: transparent;
--background-hover: rgba(0, 0, 0, 0.04);
--background-activated: rgba(0, 0, 0, 0.08);
--border-color: var(--ion-border-color, #e0e0e0);
--inner-border-width: 0 0 1px 0;
--padding-start: 16px;
--padding-end: 16px;
--min-height: 56px;
&:last-child {
--inner-border-width: 0;
}
ion-label {
font-size: 16px;
}
}
ion-item-divider {
--background: var(--ion-background-color, #f5f5f5);
--color: var(--ion-color-medium);
--padding-start: 16px;
font-weight: 600;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
5.4 输入框主题 #
scss
ion-item.item-has-focus {
--highlight-background: var(--ion-color-primary);
--highlight-height: 2px;
}
ion-input, ion-textarea {
--background: transparent;
--color: var(--ion-text-color);
--placeholder-color: var(--ion-color-medium);
--placeholder-opacity: 0.6;
--padding-start: 0;
--padding-end: 0;
font-size: 16px;
}
// 错误状态
ion-item.item-has-error {
--highlight-background: var(--ion-color-danger);
ion-label {
color: var(--ion-color-danger);
}
}
六、多主题支持 #
6.1 主题定义 #
scss
// themes/blue.scss
.theme-blue {
--ion-color-primary: #3880ff;
--ion-color-secondary: #5260ff;
--ion-toolbar-background: #3880ff;
}
// themes/green.scss
.theme-green {
--ion-color-primary: #10dc60;
--ion-color-secondary: #2dd36f;
--ion-toolbar-background: #10dc60;
}
// themes/purple.scss
.theme-purple {
--ion-color-primary: #7c4dff;
--ion-color-secondary: #b388ff;
--ion-toolbar-background: #7c4dff;
}
6.2 主题切换服务 #
typescript
// theme.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ThemeService {
private themes = ['default', 'blue', 'green', 'purple'];
private currentTheme = 'default';
constructor() {
this.loadTheme();
}
getThemes(): string[] {
return this.themes;
}
getCurrentTheme(): string {
return this.currentTheme;
}
setTheme(themeName: string) {
// 移除所有主题类
this.themes.forEach(theme => {
document.body.classList.remove(`theme-${theme}`);
});
// 添加新主题类
if (themeName !== 'default') {
document.body.classList.add(`theme-${themeName}`);
}
this.currentTheme = themeName;
this.saveTheme();
}
private saveTheme() {
localStorage.setItem('theme', this.currentTheme);
}
private loadTheme() {
const saved = localStorage.getItem('theme');
if (saved && this.themes.includes(saved)) {
this.setTheme(saved);
}
}
}
6.3 主题选择器组件 #
typescript
// theme-selector.component.ts
import { Component } from '@angular/core';
import { ThemeService } from './theme.service';
@Component({
selector: 'app-theme-selector',
template: `
<ion-list>
<ion-radio-group [value]="currentTheme" (ionChange)="onThemeChange($event)">
<ion-item *ngFor="let theme of themes">
<ion-label>{{ theme | titlecase }}</ion-label>
<ion-radio [value]="theme"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
`
})
export class ThemeSelectorComponent {
themes: string[];
currentTheme: string;
constructor(private themeService: ThemeService) {
this.themes = this.themeService.getThemes();
this.currentTheme = this.themeService.getCurrentTheme();
}
onThemeChange(event: any) {
this.themeService.setTheme(event.detail.value);
}
}
七、最佳实践 #
7.1 颜色命名规范 #
scss
// 推荐:语义化命名
:root {
--color-brand-primary: #3880ff;
--color-brand-secondary: #5260ff;
--color-text-primary: #000000;
--color-text-secondary: #666666;
--color-background-primary: #ffffff;
--color-background-secondary: #f5f5f5;
}
// 不推荐:具体颜色命名
:root {
--color-blue: #3880ff;
--color-gray: #666666;
}
7.2 主题文件组织 #
text
src/theme/
├── _variables.scss # 基础变量
├── _colors.scss # 颜色定义
├── _typography.scss # 字体样式
├── _components.scss # 组件主题
├── _platforms.scss # 平台样式
├── _dark.scss # 暗黑模式
└── main.scss # 主入口
7.3 性能优化 #
scss
// 使用CSS变量而不是重复定义
// 推荐
:root {
--primary-color: #3880ff;
}
ion-button {
--background: var(--primary-color);
}
ion-toolbar {
--background: var(--primary-color);
}
// 不推荐
ion-button {
--background: #3880ff;
}
ion-toolbar {
--background: #3880ff;
}
八、总结 #
8.1 主题定制要点 #
| 要点 | 说明 |
|---|---|
| 颜色配置 | 定义品牌颜色和语义颜色 |
| 暗黑模式 | 自动或手动切换 |
| 平台样式 | iOS和Android差异化 |
| 组件主题 | 统一组件外观 |
| 多主题 | 支持主题切换 |
8.2 下一步 #
掌握了主题定制后,接下来让我们学习 响应式布局,了解Ionic的响应式设计!
最后更新:2026-03-28