尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

鸿蒙HarmonyOS主题适配实战 —— 让深色模式成为框架默认能力,而不是逐页改造

鸿蒙HarmonyOS主题适配实战 —— 让深色模式成为框架默认能力,而不是逐页改造
📅 发布时间:2026/7/7 10:16:26

一、前言:深色模式不是"事后补",是"地基"

先看一个真实的开发场景。

团队赶进度,所有页面都用硬编码颜色写了:

// 随处可见的硬编码 Text('标题').fontColor('#182431') Column().backgroundColor('#FFFFFF') Row().backgroundColor('#F6F8FA')

上线后产品说"我们要支持深色模式"。开发者打开真机切到 Dark Mode,发现:

  1. 白底白字:#FFFFFF背景在深色模式下还是白色,文字也是白色,完全看不见。

  2. 底部边缘发白:FloatingTabBar 的渐变蒙层#66F1F3F5在深色模式下把每个页面底部都"漂白"了。

  3. 渐变刺眼:浅色柔和渐变#EEF4FF → #FFEDE2在深色模式下像两个亮色斑块,非常刺眼。

  4. 状态栏文字看不见:#182431的状态栏内容颜色在深色背景下消失。

  5. 选中态文字低对比:选中项用了蓝色背景,文字也用蓝色,低到看不清。

于是团队花了两个星期,逐页排查、逐个替换颜色值。而且每加一个新页面,深色模式就要再补一次——永远在追赶。

这个故事的根因是:

深色模式不应该是"事后补",而应该是"地基"。如果主题基础设施在项目第一天就搭好,90% 的深色适配是自动的。

本文基于 ArkUILab E011 实验,讲清楚如何在鸿蒙里搭建 Theme Foundation,让深色模式成为框架默认能力。


二、鸿蒙主题能力地图:七层体系

E011 最核心的产出,是把鸿蒙的主题能力整理成一张七层地图。请先记住一句话:

鸿蒙的主题体系不是"一个深色开关",而是一个从系统令牌到动态主题的七层体系。

HarmonyOS Theme Capability Map ├── System Token(系统令牌) │ └── $r('sys.color.*') │ text / background / card / field / separator / state / primary │ → 系统自动跟随深浅色,无需自己写 dark 资源 │ ├── Resource Color(资源颜色) │ └── resources/base/element/color.json ← 浅色值 │ └── resources/dark/element/color.json ← 深色值 │ → 自定义语义资源,系统按 colorMode 自动选择 │ ├── Semantic Token(语义令牌) │ └── ThemeTokens.ets │ ThemePageBackground() / ThemeTextPrimary() / ... │ → 项目级稳定命名,隔离"系统令牌选哪个"的决策 │ ├── Component Token(组件令牌) │ └── 未来:每个框架的专用令牌 │ → 同一语义出现至少两次后再提取 │ ├── Dynamic Theme / WithTheme(动态主题) │ └── WithTheme 支持应用内换肤 │ → v1 不用,先靠系统/资源令牌 │ ├── Material(材质) │ └── HDS blur/material APIs + ADAPTIVE 策略 │ → 未来 API 26 systemMaterial │ └── Dark Mode(深色模式) └── 跟随系统 colorMode + 令牌/资源自动切换 → 不需要自己监听模式切换

最关键的三层:

  1. System Token——$r('sys.color.*'),系统自动跟随深浅色,是你最该用的。

  2. Resource Color——$r('app.color.*'),通过base/dark资源限定符自动切换。

  3. Semantic Token——ThemeTokens.ets里的ThemePageBackground()等函数,给你的项目一个稳定的命名层。


三、令牌分层策略:四层迁移链

E011 定义了一条从系统到业务的令牌迁移链:

System Token 系统令牌(首选) ↓ Project Semantic Token 项目语义令牌(ThemeTokens.ets) ↓ Component Token 框架/组件令牌(同一语义出现两次后提取) ↓ Business Color 业务/内容/演示颜色(保持本地,标注用途)

对应的七条规则:

  1. 默认用系统令牌:文字、页面、卡片、组件、输入框、分割线、点击/悬停、主色都用$r('sys.color...')。

  2. 语义令牌用于框架稳定命名:当框架需要一个不依赖"具体选哪个系统令牌"的稳定名字时,用ThemeTokens.ets。

  3. 应用资源颜色用于需要 dark 分值的语义:只有当一个值需要不同的浅色/深色值,且没有系统令牌能表达这个语义时,才加$r('app.color...')。

  4. 组件令牌等重复出现后再提取:同一语义至少出现两次或成为框架 API 表面时,才提取组件令牌。

  5. 业务颜色保持本地:但要标注是"内容身份""数据可视化""渐变演示""蒙层实验"还是"官方 API 探针"。

  6. 不要因为效果在深色模式下失败就删除它:先问"它是否应该变成一个有 base/dark 分值的语义资源"。

  7. 填充主控件用专用按钮语义对:不要用通用 accent 令牌,用ThemePrimaryButtonBackground()+ThemePrimaryButtonForeground()。


四、系统令牌:深色模式的"免费午餐"

4.1 什么是系统令牌?

鸿蒙提供了一套系统级颜色令牌,通过$r('sys.color.*')引用。这些令牌自动跟随系统深浅色模式——你不需要写任何 dark 资源,系统会帮你切换。

E011 审计发现,ArkUILab 活跃代码中使用了18 个系统颜色令牌:

ohos_id_color_background 页面背景 ohos_id_color_sub_background 次级页面背景 ohos_id_color_list_card_bg 卡片背景 ohos_id_color_component_normal 组件常规填充 ohos_id_color_component_activated 组件激活态 ohos_id_color_text_primary 主要文字 ohos_id_color_text_secondary 次要文字 ohos_id_color_text_tertiary 第三级文字 ohos_id_color_text_field_bg 输入框背景 ohos_id_color_text_field_sub_bg 输入框次级背景 ohos_id_color_list_separator 列表分割线 ohos_id_color_subheading_separator 子标题分割线 ohos_id_color_click_effect 点击效果 ohos_id_color_hover 悬停效果 ohos_id_color_primary 主色 ohos_id_color_secondary 次色 ohos_id_color_tertiary 第三色 ohos_id_color_fourth 第四色

4.2 怎么用?

直接在代码里引用:

// 文字 Text('标题').fontColor($r('sys.color.ohos_id_color_text_primary')) Text('说明').fontColor($r('sys.color.ohos_id_color_text_secondary')) // 背景 Column().backgroundColor($r('sys.color.ohos_id_color_list_card_bg')) // 分割线 Divider().color($r('sys.color.ohos_id_color_list_separator'))

这是深色模式最省心的方式——切到 Dark Mode 时,这些令牌自动变成深色版本的值,你什么都不用做。

4.3 审计数据

E011 迁移后扫描结果:

96 处 $r('sys.color...') 引用 18 个活跃系统令牌

最常用的类别:text_secondary、list_card_bg、list_separator、primary、component_normal、text_field_bg。


五、语义令牌层:ThemeTokens.ets

5.1 为什么需要语义令牌?

系统令牌很好,但有一个问题:名字是系统级的,不是项目级的。

如果你的代码里到处写$r('sys.color.ohos_id_color_sub_background'),当某天你想把页面背景换一个系统令牌,要全局搜索替换。更糟的是,不同开发者可能对"页面背景"用了不同的系统令牌,导致不一致。

语义令牌层解决这个问题:给项目一个稳定的命名,隔离"选哪个系统令牌"的决策。

5.2 ThemeTokens.ets 的结构

// 页面背景 export function ThemePageBackground(): ResourceColor { return $r('sys.color.ohos_id_color_sub_background'); } // 卡片/表面背景 export function ThemeSurfaceBackground(): ResourceColor { return $r('sys.color.ohos_id_color_list_card_bg'); } // 组件常规填充 export function ThemeComponentBackground(): ResourceColor { return $r('sys.color.ohos_id_color_component_normal'); } // 文字 export function ThemeTextPrimary(): ResourceColor { return $r('sys.color.ohos_id_color_text_primary'); } export function ThemeTextSecondary(): ResourceColor { return $r('sys.color.ohos_id_color_text_secondary'); } export function ThemeTextTertiary(): ResourceColor { return $r('sys.color.ohos_id_color_text_tertiary'); } // 分割线 export function ThemeDividerColor(): ResourceColor { return $r('sys.color.ohos_id_color_list_separator'); } // 输入框 export function ThemeTextFieldBackground(): ResourceColor { return $r('sys.color.ohos_id_color_text_field_bg'); }

5.3 完整语义令牌清单

E011 沉淀的语义令牌共 25+ 个,按用途分类:

类别

令牌

底层来源

页面

ThemePageBackground()

sys.color.sub_background

表面

ThemeSurfaceBackground()

sys.color.list_card_bg

组件

ThemeComponentBackground()

sys.color.component_normal

文字

ThemeTextPrimary/Secondary/Tertiary()

sys.color.text_*

强调

ThemeAccentColor()

sys.color.primary

OnAccent

ThemeOnAccentColor()

app.color.arkuilab_on_accent

主按钮

ThemePrimaryButtonBackground()

sys.color.component_activated

主按钮前景

ThemePrimaryButtonForeground()

app.color.arkuilab_on_accent

分割线

ThemeDividerColor()

sys.color.list_separator

输入框

ThemeTextFieldBackground()

sys.color.text_field_bg

透明

ThemeTransparentColor()/ThemeTransparentWhiteColor()

固定透明值

阴影

ThemeCardShadowColor()

app.color.arkuilab_shadow_card

蒙层

ThemeOverlayScrimColor()

app.color.arkuilab_overlay_scrim

搜索菜单

ThemeSearchMenuBackground/Border()

app.color.arkuilab_search_menu_*

渐变

ThemeGradientTonal/Cool/Warm/Violet/Accent Start/End()

app.color.arkuilab_gradient_*

底部蒙层

ThemeBottomGradientMask()

app.color.arkuilab_bottom_gradient_mask

浮层材质

ThemeFloatingMaterialColor()

app.color.arkuilab_floating_material_light

5.4 使用方式

在业务代码里,优先用语义令牌,不要直接用系统令牌:

import { ThemeTextPrimary, ThemePageBackground, ThemeSurfaceBackground } from './theme/ThemeTokens'; build() { Column() { Text('标题').fontColor(ThemeTextPrimary()) } .backgroundColor(ThemePageBackground()) }

例外:在一次性令牌实验或官方 API 探针代码里,直接用$r('sys.color...')是允许的。


六、base/dark 资源限定符:自定义语义的双值

6.1 什么时候需要自定义资源?

系统令牌覆盖了大部分场景,但有些语义系统令牌表达不了:

  • 卡片阴影的 alpha 值

  • Overlay 蒙层的 alpha 值

  • OnAccent 文字颜色(在激活蓝背景上的前景色)

  • 搜索菜单的半透明材质

  • 渐变色块

  • 底部渐变蒙层

  • 浮层材质颜色

这些需要$r('app.color.*')——通过resources/base和resources/dark的资源限定符自动切换。

6.2 浅色值:base/element/color.json

{ "color": [ { "name": "arkuilab_shadow_card", "value": "#18243114" }, { "name": "arkuilab_overlay_scrim", "value": "#1824311F" }, { "name": "arkuilab_search_menu_background", "value": "#F2FFFFFF" }, { "name": "arkuilab_search_menu_border", "value": "#FFFFFFFF" }, { "name": "arkuilab_on_accent", "value": "#FFFFFFFF" }, { "name": "arkuilab_gradient_tonal_start", "value": "#EEF4FF" }, { "name": "arkuilab_gradient_tonal_end", "value": "#FFEDE2" }, { "name": "arkuilab_bottom_gradient_mask", "value": "#66F1F3F5" }, { "name": "arkuilab_floating_material_light", "value": "#FFFFFFFF" } ] }

6.3 深色值:dark/element/color.json

{ "color": [ { "name": "arkuilab_shadow_card", "value": "#00000066" }, { "name": "arkuilab_overlay_scrim", "value": "#00000066" }, { "name": "arkuilab_search_menu_background", "value": "#F21D2024" }, { "name": "arkuilab_search_menu_border", "value": "#33FFFFFF" }, { "name": "arkuilab_on_accent", "value": "#FFFFFFFF" }, { "name": "arkuilab_gradient_tonal_start", "value": "#1B2738" }, { "name": "arkuilab_gradient_tonal_end", "value": "#35271F" }, { "name": "arkuilab_bottom_gradient_mask", "value": "#6613171D" }, { "name": "arkuilab_floating_material_light", "value": "#FF1D2024" } ] }

关键点:

  • 两个 JSON 文件的key 完全一致,只是值不同。

  • 系统根据当前 colorMode自动选择读哪个文件——你不需要写if (isDark)。

  • 浅色柔和渐变#EEF4FF → #FFEDE2在深色模式下变成深色渐变#1B2738 → #35271F,保留了"柔和渐变"的视觉语言,只是亮度适配了暗色环境。

6.4 ⚠️ 踩坑一:底部蒙层在深色模式发白

这是 E011 最经典的踩坑:

FloatingTabBar 底部有一个渐变蒙层,浅色值是#66F1F3F5(半透明浅灰)。如果不提供 dark 值,深色模式下这个浅灰蒙层会让每个页面底部都发白。

修复:提供 dark 值#6613171D(半透明深色),让蒙层在深色模式下也是暗的。

规则:底部边缘是主题审计的一部分。TabBar 蒙层、模糊材质、渐变 overlay 必须和页面背景一起审计。


七、主题审计报告:真实数据

E011 迁移后的审计数据:

7.1 系统令牌使用

96 处 $r('sys.color...') 引用 18 个活跃系统令牌 最常用:text_secondary / list_card_bg / list_separator / primary / component_normal / text_field_bg

7.2 硬编码颜色残留

130 处 HEX 引用 75 个不同 HEX 值 Color.White:1 处(FloatingTabBarShell 的 HDS systemMaterialEffect.lightColor,保留为官方探针) Color.Black / Color.Gray / RGB / ARGB:0 处

7.3 必须后续迁移的硬编码

残留位置

问题

对策

EntryAbility.ets状态栏内容色#182431

不自适应

需要uiAppearance或配置感知的窗口栏更新

Menu/ActionSheet/Feedback titleBar 透明背景#00FFFFFF

应该用令牌

下次改动这些文件时迁移到ThemeTransparentWhiteColor()

MenuLabDestination自定义 Select 样本

有意保留的视觉探针

重复使用后应变成组件令牌

7.4 允许保留的硬编码

残留位置

为什么保留

转场/Action/Menu/Feedback Lab 的演示渐变

实验视觉语言的一部分

Quick Access 条目的业务身份色

内容身份,不是结构色

ActionSheet 蒙层值

等选择面框架有专用组件令牌后再迁移

HDS 官方模糊 TabBar 蒙层#66F1F3F5

等设备对比确认令牌替代后迁移


八、迁移实战:怎么改才对

8.1 迁移前的错误写法

// ❌ 硬编码结构色 Text('标题').fontColor('#182431') Text('说明').fontColor('#56606C') Column().backgroundColor('#F6F8FA') Column().backgroundColor('#FFFFFF') // 卡片 Divider().color('#E5E8EE') Column().backgroundColor('#F0F1F5') // 输入框

8.2 迁移后的正确写法

// ✅ 语义令牌 Text('标题').fontColor(ThemeTextPrimary()) Text('说明').fontColor(ThemeTextSecondary()) Column().backgroundColor(ThemePageBackground()) Column().backgroundColor(ThemeSurfaceBackground()) // 卡片 Divider().color(ThemeDividerColor()) Column().backgroundColor(ThemeTextFieldBackground()) // 输入框

8.3 渐变的正确处理

不要因为渐变在深色模式下失败就删掉它。正确的做法是把渐变终点变成有 base/dark 分值的语义资源:

// ❌ 硬编码渐变终点 .linearGradient({ angle: 135, colors: [['#EEF4FF', 0], ['#FFEDE2', 1]] }) // ✅ 语义渐变令牌(base/dark 自动切换) .linearGradient({ angle: 135, colors: [ [ThemeGradientTonalStart(), 0], [ThemeGradientTonalEnd(), 1] ] })

规则:主题迁移不是视觉拍平。如果渐变、蒙层、材质是框架身份的一部分,保留效果,把终点/蒙层移到语义 base/dark 资源里。

8.4 主按钮的正确处理

每个填充背景令牌都需要一个前景搭档:

// ❌ 选中态文字用了背景/激活色,低对比 MenuItem({ content: '选项' }) .selectedOptionFontColor($r('sys.color.ohos_id_color_activated')) // 蓝字蓝底 .selectedOptionBgColor($r('sys.color.ohos_id_color_activated')) // ✅ 填充背景用激活蓝,前景用 onAccent 白 MenuItem({ content: '选项' }) .selectedOptionBgColor(ThemePrimaryButtonBackground()) // 蓝底 .selectedOptionFontColor(ThemePrimaryButtonForeground()) // 白字

规则:蓝色填充控件应该用主按钮语义对(ThemePrimaryButtonBackground+ThemePrimaryButtonForeground),不要用通用 accent 令牌。


九、框架审计:哪些框架已就绪

E011 对 ArkUILab 的所有框架做了主题就绪审计:

框架

主题状态

说明

Navigation Framework

基本就绪

HDS Navigation + title bar 令牌用系统色;窗口状态栏有一个 gap

Navigation Header Framework

v1 就绪

Header 标题/菜单/搜索已迁移到系统/语义令牌

FloatingTabBar Framework

v1 就绪

浮层材质和底部渐变蒙层用 base/dark 资源

ApplicationShell

就绪

根背景用ThemePageBackground()

Overlay Framework

v1 就绪

下拉浮层蒙层/卡片/输入/文字已迁移

Menu Framework

部分

大部分用系统令牌;自定义视觉探针保留;API 26 systemMaterial 待 SDK

Selection Framework

部分

核心 text/card 令牌已有;蒙层/透明值待迁移

Feedback Framework

基本就绪

用系统 card/text 令牌;hero 渐变保留为演示视觉

Search Framework

v1 就绪

会话页/搜索输入/菜单表面/边线/占位/结果行已迁移

结论:9 个框架中 5 个 v1 就绪,3 个部分就绪,1 个基本就绪。没有完全未就绪的框架。


十、最佳实践清单

10.1 禁止事项

  • ❌ 不要用Color.White、Color.Black、Color.Gray做结构 UI。

  • ❌ 不要用#FFFFFF、#000000、#182431、#56606C做结构 UI。

  • ❌ 不要用 RGB / ARGB API 调用做结构 UI。

  • ❌ 不要在实验里覆盖 app colorMode,除非实验明确研究主题覆盖。

  • ❌ 不要创建ThemeManager,除非有真实的用户可选应用内主题需求。

10.2 推荐事项

  • ✅ 新框架代码用ThemeTokens.ets。

  • ✅ 一次性令牌实验可直接用$r('sys.color...')。

  • ✅ 需要 dark 分值时用resources/base+resources/dark。

  • ✅ 透明色当工具令牌用(ThemeTransparentColor/ThemeTransparentWhiteColor),不当视觉设计令牌。

  • ✅ 渐变保留,但每个结构渐变终点用ThemeGradient...()令牌。

  • ✅ 填充主控件用ThemePrimaryButtonBackground()+ThemePrimaryButtonForeground()。

  • ✅ 底部边缘蒙层和材质颜色必须是主题资源。

  • ✅ 主题编辑后跑 HAP 构建验证。

10.3 审计命令

E011 沉淀了三条审计命令,建议加入 CI:

# 统计系统令牌使用 rg -o '\$r('\''sys\.color\.[^'\'']+'\''\)' entry/src/main/ets | sort | uniq -c | sort -nr # 统计应用资源令牌使用 rg -o '\$r('\''app\.color\.[^'\'']+'\''\)' entry/src/main/ets | sort | uniq -c | sort -nr # 扫描禁用的硬编码颜色 rg -n '(Color\.(White|Black|Gray|Grey)|#[0-9A-Fa-f]{3,8}\b|rgb\(|rgba\(|argb\(|ARGB|RGB)' entry/src/main/ets entry/src/main/resources

10.4 迁移检查清单

  • 页面背景用ThemePageBackground()

  • 卡片/Sheet/Popover 用ThemeSurfaceBackground()

  • 组件填充/输入芯片用ThemeComponentBackground()或ThemeTextFieldBackground()

  • 文字用ThemeTextPrimary/Secondary/Tertiary()

  • 分割线/边框用ThemeDividerColor()

  • 主操作用ThemeAccentColor()+ThemeOnAccentColor()

  • 填充主按钮用ThemePrimaryButtonBackground()+ThemePrimaryButtonForeground()

  • 结构渐变用ThemeGradient...()语义对

  • 底部蒙层/模糊材质用ThemeBottomGradientMask()/ThemeFloatingMaterialColor()

  • 选中态前景与背景对比度足够

  • 蒙层/阴影用ThemeTokens.ets暴露的应用资源

  • HAP 构建通过


十一、常见错误对照表

错误做法

问题

正确做法

fontColor('#182431')

深色模式下文字消失

ThemeTextPrimary()

backgroundColor('#FFFFFF')

深色模式白底

ThemeSurfaceBackground()

backgroundColor('#F6F8FA')

深色模式浅灰底

ThemePageBackground()

渐变硬编码#EEF4FF

深色模式刺眼

ThemeGradientTonalStart()

底部蒙层只有浅色值

每个页面底部发白

提供 dark 资源值

选中态蓝底蓝字

低对比看不清

ThemePrimaryButtonForeground()白字

Color.White做结构色

不自适应

语义令牌

深色失败就删渐变

丢失视觉语言

保留渐变,终点用 base/dark 资源

每个页面自己写if (isDark)

不可维护

用令牌/资源自动切换

直接到处用$r('sys.color...')

不一致、难维护

用ThemeTokens.ets语义层

accent 令牌做填充按钮

语义太宽泛

用ThemePrimaryButton*专用对

状态栏内容色硬编码

深色下不可见

需要uiAppearance或配置感知


十二、Review 教训:四条经验

E011 在真机 review 后总结了四条关键教训:

12.1 主题迁移不是视觉拍平

如果渐变、蒙层、材质是框架身份的一部分,保留效果,把终点/蒙层移到语义 base/dark 资源里。

不要为了"适配深色模式"把所有渐变都删掉变成纯色——那会让应用失去视觉个性。正确的做法是让渐变在深色模式下也有对应的深色版本。

12.2 令牌编码的是角色,不只是颜色

ThemeAccentColor()太宽泛,不适合填充控件。ThemePrimaryButtonBackground()更清晰,映射到系统激活蓝。

一个令牌的名字应该表达用途("主按钮背景"),而不是色相("蓝色")。这样当你换品牌色时,只需要改一个地方。

12.3 每个填充背景令牌都需要前景搭档

Icon Select 的回归就是因为选中态文字用了背景/激活色,而不是ThemePrimaryButtonForeground()。

定义ThemePrimaryButtonBackground()的同时必须定义ThemePrimaryButtonForeground()。否则一定会有人把低对比度的文字放到同色背景上。

12.4 底部边缘是主题审计的一部分

TabBar 蒙层、模糊材质、渐变 overlay 必须和页面背景一起审计。

底部边缘很容易被忽略——它不在页面正中间,但在每个页面都出现。一个#66F1F3F5的浅色蒙层会让整个应用在深色模式下底部发白。

12.5 构建成功 ≠ 主题正确

Build success 证明了类型安全,但只有模式切换才能发现对比度、漂白和过度拍平的问题。

HAP 构建通过只能证明代码能编译,不能证明深色模式看起来对。真机切到 Dark Mode 走一遍是主题验证的必要步骤。


十三、当前限制与后续方向

E011 的 Theme Foundation v1 已经成立,但仍有后续工作:

待办项

说明

状态栏/导航栏内容色

需要uiAppearance或配置感知的窗口栏更新

透明 titleBar 值

迁移到ThemeTransparentWhiteColor()

选择面/菜单组件令牌

等设备 review 后、重复使用稳定后提取

API 26systemMaterial

等本地 SDK 暴露后验证

API 26menuSystemMaterial

同上

API 26uiAppearance

同上

CI 审计脚本

自动扫描禁用的结构硬编码颜色

暂不创建:

  • ThemeManager—— 没有真实用户可选主题需求时不需要。

  • ThemeConfiguration—— 没有本地/用户主题覆盖实验时不需要。

  • 组件令牌注册表 —— 等重复的组件级语义出现后再提取。


十四、构建验证

DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk \ /Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw assembleHap --no-daemon

E011 构建结果:

CompileArkTS passed PackageHap passed BUILD SUCCESSFUL

十五、写在最后

深色模式不是"事后补的体力活",而是"第一天就该搭好的地基"。如果你的主题基础设施在项目开始时就搭对,90% 的深色适配是自动的——系统令牌帮你切,base/dark 资源帮你切,你只需要管那 10% 的自定义语义。

鸿蒙的主题体系给了你足够的工具:

  • sys.color.*系统令牌——免费自动切换

  • base/dark资源限定符——自定义语义的双值

  • ThemeTokens.ets语义层——项目级稳定命名

  • HDS 材质 ADAPTIVE 策略——模糊/材质自动适配

你需要做的是选对令牌、分层管理、审计到底。

记住这几条口诀:

系统令牌优先用,语义令牌稳命名。 base dark 双值备,自动切换不用写 if。 渐变别拍平,终点存资源。 填充按钮有搭档,背景前景配对走。 底部边缘要审计,蒙层发白坑全站。 Color.White 别用,#182431 别留。 构建过了不算对,真机切暗才算行。

本文的实现基于 ArkUILab 项目 E011 实验。它不是最终产品,但已经形成了一个可以让每个新框架自动继承的主题基础设施。如果你正在从零开始做一个鸿蒙应用,或者在给现有应用补深色模式,可以直接复用这套令牌分层策略和审计方法作为起点。

主题适配看似只是"换个深色背景",背后却涉及令牌分层、资源限定符、语义命名、渐变保留、前景搭档、底部边缘审计和真机验证等多个维度。把这些维度拆清楚,你的深色模式就不会是"逐页改造的体力活"了。

相关新闻

  • 计算机Java毕设实战-基于前后端分离的区域性医院诊疗管理系统的设计与实现 基于 SpringBoot+Vue 的基层医院就医服务管理系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • Palworld存档数据转换方案:实现游戏存档的JSON双向解析
  • WeChatMsg:3大突破性能力重塑你的数字记忆主权

最新新闻

  • 3步开启ROS机器人仿真:从零到实战的wpr_simulation完整指南
  • XHS-Downloader终极指南:小红书无水印下载神器完整教程
  • AEUX插件实战指南:5步打通Figma/Sketch到After Effects动画工作流
  • CPU 中断与 DMA 实战解析:从 I/O 请求到数据就绪的 3 种控制方式性能对比
  • Calico BGP路由反射器翻车实录:一次跨节点Pod间单向通信故障的深度排查与修复
  • 胡桃讲编程:往生堂开课!解锁和电脑对话的魔法

日新闻

  • Android逆向分析全能助手:集成化工具链与自动化工作流设计
  • 面搜索(Faceted Search)原理与工程实践指南
  • 神经网络调参避坑指南:从5个常见Loss曲线形态定位超参数问题

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号