技术栈:HarmonyOS 5.0 + ArkTS + AppStorage
适用场景:应用主题切换、无障碍适配、华为应用市场审核
前言
深色模式已成为现代应用的标配功能。华为应用市场审核对深色模式有严格要求,所有文字必须清晰可见。本文将介绍如何实现符合WCAG标准的深色模式适配。
一、WCAG对比度标准
WCAG(Web Content Accessibility Guidelines)定义了文字对比度标准:
| 级别 | 正常文本 | 大文本 |
|---|---|---|
| AA级 | ≥ 4.5:1 | ≥ 3:1 |
| AAA级 | ≥ 7:1 | ≥ 4.5:1 |
二、主题颜色定义
2.1 浅色主题
typescript
export const LightTheme: ThemeColors = {
pageBg: '#F8F9FA',
cardBg: '#FFFFFF',
cardBgSecondary: '#F5F5F5',
// 文字色 - 符合WCAG标准
textPrimary: '#1A1A1A', // 对比度 16.1:1
textSecondary: '#595959', // 对比度 7.0:1
textTertiary: '#737373', // 对比度 4.6:1
divider: '#EEEEEE',
border: '#E5E5E5',
buttonBg: '#F0F0F0',
shadowColor: 'rgba(0, 0, 0, 0.08)',
};
2.2 深色主题
typescript
export const DarkTheme: ThemeColors = {
pageBg: '#121212',
cardBg: '#1E1E1E',
cardBgSecondary: '#2A2A2A',
// 文字色 - 符合WCAG标准
textPrimary: '#FFFFFF', // 对比度 15.3:1
textSecondary: '#CCCCCC', // 对比度 9.7:1
textTertiary: '#999999', // 对比度 5.1:1
divider: '#333333',
border: '#404040',
buttonBg: '#2A2A2A',
shadowColor: 'rgba(0, 0, 0, 0.3)',
};
2.3 主题接口定义
typescript
export interface ThemeColors {
pageBg: string;
cardBg: string;
cardBgSecondary: string;
textPrimary: string;
textSecondary: string;
textTertiary: string;
divider: string;
border: string;
buttonBg: string;
shadowColor: string;
}
三、主题管理器
typescript
export class ThemeManager {
private static isDarkMode: boolean = false;
private static listeners: Array<(isDark: boolean) => void> = [];
static setDarkMode(isDark: boolean): void {
ThemeManager.isDarkMode = isDark;
ThemeManager.listeners.forEach(listener => listener(isDark));
}
static getIsDarkMode(): boolean {
return ThemeManager.isDarkMode;
}
static getTheme(): ThemeColors {
return ThemeManager.isDarkMode ? DarkTheme : LightTheme;
}
static addListener(listener: (isDark: boolean) => void): void {
ThemeManager.listeners.push(listener);
}
static removeListener(listener: (isDark: boolean) => void): void {
const index = ThemeManager.listeners.indexOf(listener);
if (index > -1) ThemeManager.listeners.splice(index, 1);
}
}
四、页面中使用主题
4.1 使用AppStorage实现全局状态
typescript
@Entry
@Component
struct MainPage {
@StorageLink('appDarkMode') isDarkMode: boolean = true;
getBgColor(): string {
return this.isDarkMode ? '#0D1117' : '#F5F5F5';
}
getTextPrimary(): string {
return this.isDarkMode ? '#FFFFFF' : '#1A1A1A';
}
getTextSecondary(): string {
return this.isDarkMode ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.6)';
}
private toggleTheme(): void {
this.isDarkMode = !this.isDarkMode;
AppStorage.setOrCreate('appDarkMode', this.isDarkMode);
PreferencesUtil.putBoolean('app_dark_mode', this.isDarkMode);
}
build() {
Column() {
Text('标题')
.fontSize(24)
.fontColor(this.getTextPrimary())
Text('副标题')
.fontSize(14)
.fontColor(this.getTextSecondary())
Button('切换主题')
.onClick(() => this.toggleTheme())
}
.backgroundColor(this.getBgColor())
}
}
4.2 跟随系统主题
typescript
import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
@Entry
@Component
struct SettingsPage {
@StorageProp('currentColorMode') @Watch('onColorModeChange')
currentColorMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
@State themeMode: string = 'system'; // 'system' | 'light' | 'dark'
onColorModeChange(): void {
if (this.themeMode === 'system') {
const isDark = this.currentColorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
AppStorage.setOrCreate('appDarkMode', isDark);
}
}
private applyThemeMode(): void {
let isDark: boolean;
if (this.themeMode === 'system') {
isDark = this.currentColorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
} else {
isDark = this.themeMode === 'dark';
}
AppStorage.setOrCreate('appDarkMode', isDark);
PreferencesUtil.putString('theme_mode', this.themeMode);
}
}
五、对比度检查工具
推荐使用在线工具检查颜色对比度:
- WebAIM Contrast Checker: webaim.org/resources/c...
- Coolors Contrast Checker: coolors.co/contrast-ch...
六、避坑指南
- 华为审核要求:深色模式下所有文字必须清晰可见
- @StorageLink vs @StorageProp:前者双向绑定,后者只读
- 颜色透明度 :使用
rgba()时注意透明度对对比度的影响 - 图标适配:深色模式下图标也需要适配
总结
本文介绍了HarmonyOS深色模式的完整实现方案,包括符合WCAG标准的颜色定义、主题管理器、页面使用方法等。正确的深色模式适配不仅能通过应用市场审核,还能提升用户体验。