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