【OpenHarmony/HarmonyOs 】深色模式适配实践从颜色资源到页面状态联动深色模式不是把背景改黑这么简单。对于「化学视界」这种内容型学习 App 来说元素分类、方程式类型、知识标签、卡片层级都依赖颜色表达。本文记录我在项目中做深色模式适配的思路。一、为什么深色模式要认真做学习 App 的使用场景很复杂白天在课堂或书桌旁查资料。晚上复习错题。长时间阅读知识点。平板上横屏看周期表。如果深色模式只把背景变黑可能会出现文字对比度不够。彩色卡片太刺眼。元素分类不清楚。弹窗层级不明显。按钮状态难以识别。所以我在项目里把深色模式当成一套完整视觉系统来做。二、颜色资源分层项目中有浅色和深色两套颜色资源。浅色环境中{name:primary_color,value:#2E7D32}, {name:surface_color,value:#FFFFFF}, {name:background_color,value:#F5F5F5}深色环境中{name:primary_color,value:#81C784},{name:surface_color,value:#1E1E1E},{name:background_color,value:#121212}我没有直接在页面里写死所有颜色而是尽量使用资源引用。这样后续调整主题时不需要到每个页面里找颜色。三、页面如何感知系统色彩模式入口中会把系统颜色模式写入全局状态AppStorage.setOrCreate(sysColorMode,this.context.config.colorMode); onConfigurationUpdate(config: Configuration): void {AppStorage.setOrCreate(sysColorMode,config.colorMode); }页面中通过StorageLink读取StorageLink(sysColorMode)sysColorMode: number ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;这样页面不需要手动传参也不需要自己监听入口生命周期。系统颜色变化后相关页面可以自动响应。四、判断当前是否为深色环境页面中封装判断函数privateisDarkTheme(): boolean {returnthis.sysColorMode ConfigurationConstant.ColorMode.COLOR_MODE_DARK; }这个小函数很有用。比如方程式、知识库、元素周期表都需要根据深浅色返回不同颜色。五、元素周期表的颜色适配周期表是颜色最复杂的页面因为不同元素类别本来就需要不同色块。浅色环境中可以使用比较明亮的背景色深色环境中则需要降低亮度提高文字可读性getCategoryTextColor(category: ElementCategory):string{if(this.isDarkTheme()) {constcolorMap: RecordElementCategory,string {alkali_metal:#FF8A80,transition_metal:#90CAF9,nonmetal:#80DEEA,halogen:#CE93D8};returncolorMap[category] ||#B0B0B0; }constcolorMap: RecordElementCategory,string {alkali_metal:#C62828,transition_metal:#1565C0,nonmetal:#00838F,halogen:#6A1B9A};returncolorMap[category] ||#757575; }深色模式下我更关注“文字能不能看清”而不是保持和浅色完全一样的视觉效果。六、方程式页面的深色适配方程式页面有很多反应类型标签getTypeColor(type: EquationType):string{if(this.isDarkTheme()) {constcolorMap: Recordstring,string {combination:#1A2D3D,decomposition:#1B3D1B,replacement:#3D2E1B,combustion:#3D1B1B};returncolorMap[type] ||#2A2A2A; }constcolorMap: Recordstring,string {combination:#E3F2FD,decomposition:#E8F5E9,replacement:#FFF3E0,combustion:#FFEBEE};returncolorMap[type] ||#F5F5F5; }这类分类色如果不单独适配深色背景下很容易失去层次。七、知识库页面的颜色适配知识库也有分类基本概念。化学定律。原理。实验。周期律。有机化学。化学与生活。每个分类都有自己的颜色和图标。深色环境下我让背景色更沉稳文字色更亮一些避免整页变成一片灰。八、我做深色模式时踩过的点1. 不能只改背景背景变黑后卡片、分割线、弹窗遮罩、按钮、标签、阴影都要重新看一遍。2. 彩色标签要重新配色浅色模式中很柔和的浅蓝、浅绿在深色模式里可能变得发灰或不清晰。3. 文字颜色不能太暗学习 App 阅读时间长文字对比度一定要足够。4. 弹窗遮罩要更明显深色模式下弹窗和背景都偏暗如果遮罩不够明显层级会混在一起。九、为什么要用资源色而不是到处写色值开发初期如果每个页面都直接写颜色看起来速度很快。但项目页面一多就会出现几个问题同一种背景色在不同页面不一致。想调整主色时需要全局搜索。深色模式很难统一替换。后续维护容易漏改。所以我在项目里尽量把基础色放到资源文件再在页面里通过$r(app.color.xxx)引用。例如卡片背景.backgroundColor($r(app.color.surface_color))页面背景.backgroundColor($r(app.color.background_color))文字颜色.fontColor($r(app.color.text_primary))这样写的好处是页面代码表达的是“这是主文字色”“这是卡片背景色”而不是一个孤立的十六进制颜色。十、深色模式和学习场景的关系我做深色模式时并不是单纯为了功能完整而是考虑到学习场景。晚上复习时用户可能长时间看知识点和错题解析。如果页面背景太亮会很累如果文字太暗又读不清。所以深色模式的核心是阅读舒适度。对于「化学视界」这种 App深色模式尤其要关注知识详情的正文行高。方程式的高亮颜色。周期表色块对比。错题解析文字。弹窗和背景层级。十一、深色模式开发建议我总结了几个实践建议 所有基础色尽量放资源文件。 页面只判断模式不到处写重复逻辑。 高信息密度页面要重点测试。 内容阅读页优先保证文字对比度。 分类色要分别适配不要简单复用。十二、总结深色模式是一套完整体验不是一个开关。在「化学视界」中我从颜色资源、全局状态、页面判断、分类色映射几个层面完成适配。这样做的结果是夜间阅读更舒服。元素和方程式分类仍然清晰。卡片和弹窗层级更稳定。页面风格保持一致。如果你的 App 也有大量内容和分类色深色模式一定要尽早规划而不是最后临时补。