news 2026/8/12 20:05:46

HarmonyOS7 颜色 Token 让主题更稳:ArkUI/ArkTS 实战拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS7 颜色 Token 让主题更稳:ArkUI/ArkTS 实战拆解


文章目录

      • 前言
      • 为什么这个问题经常被写乱
      • 场景:品牌页接入深色模式
      • 常用颜色语义
      • 实操步骤
      • 先把页面目标想清楚
      • 完整示例:语义颜色驱动品牌页
      • 把关键代码一段段拆开
      • 容易踩坑的点
      • 优化建议
      • 颜色 Token 要先分清语义
      • 写在最后

前言

颜色 token 的重点不是把色值藏起来,而是让颜色具备语义。品牌色、危险色、辅助文字、页面背景这些角色稳定了,主题切换才不会牵一发动全身。

这篇单独聊品牌页这个场景。重点不是堆 API,而是把品牌色、危险色、辅助文字和背景色按语义收口,避免主题切换时到处改组件。

为什么这个问题经常被写乱

颜色 Token 让主题更稳 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。

所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。

场景:品牌页接入深色模式

颜色 token 最容易在项目中后期暴露价值。早期页面少,按钮直接写#0A59F7,危险操作直接写#D92D20,看起来没什么问题。等品牌升级、深色模式上线、营销页要换主题时,散落在页面里的色值就会变成维护成本。

品牌页尤其明显:主按钮、选中态、活动标签、说明文字、分割线、卡片背景都和颜色有关。如果每个组件都直接绑定一个具体色值,主题切换时就要到处改。语义 token 的做法是让组件只关心“这是品牌色”“这是危险色”“这是弱文本”,不关心它今天具体是哪个蓝。

颜色 token 的价值不是少写几个色值,而是让主题变更不会扩散到每个组件。

常用颜色语义

Token浅色值深色值用途
colorBrand#0A59F7#6EA8FF主按钮、选中态
colorDanger#D92D20#FF8A80删除、异常
colorSuccess#0A7F3F#62D28F成功、完成
colorTextPrimary#111111#F2F4F8主文案
colorTextSecondary#666666#B8C0CC辅助说明
colorPageBg#F5F7FA#111318页面背景
colorCardBg#FFFFFF#1C2028卡片背景

实操步骤

  1. 先按语义列出页面用色,不要按色相列blue1red2
  2. 页面组件只引用 token 方法,不直接散写色值。
  3. 深浅主题切换时只改变 token 返回值,不改页面结构。
  4. 危险、成功、品牌三个语义要分开,不能拿品牌色硬顶所有状态。
  5. 检查卡片背景和页面背景的层级,暗色模式下尤其容易糊成一片。

先把页面目标想清楚

在真正写代码之前,先别急着盯着 API。更有用的做法是先想清楚:这个页面到底想解决什么问题,用户最在意的反馈是什么,哪些状态必须一直保持一致。

当你先把这条主线想明白,再回头看组件和状态设计,很多选择都会顺理成章。对小白来说,这一步尤其重要,因为它能帮你从“照着抄”慢慢过渡到“看得懂、改得动”。

完整示例:语义颜色驱动品牌页

@Entry@Componentstruct ColorTokenPage{@StatedarkMode:boolean=false@StateselectedPlan:string='pro'privatebrand():string{returnthis.darkMode?'#6EA8FF':'#0A59F7'}privatedanger():string{returnthis.darkMode?'#FF8A80':'#D92D20'}privatesuccess():string{returnthis.darkMode?'#62D28F':'#0A7F3F'}privatetextPrimary():string{returnthis.darkMode?'#F2F4F8':'#111111'}privatetextSecondary():string{returnthis.darkMode?'#B8C0CC':'#666666'}privatepageBg():string{returnthis.darkMode?'#111318':'#F5F7FA'}privatecardBg():string{returnthis.darkMode?'#1C2028':'#FFFFFF'}@BuilderPlanCard(name:string,price:string,plan:string){Column({space:8}){Row(){Text(name).fontSize(18).fontWeight(FontWeight.Bold).fontColor(this.textPrimary())Blank()Text(this.selectedPlan===plan?'已选':'可选').fontSize(12).fontColor(this.selectedPlan===plan?this.success():this.textSecondary())}.width('100%')Text(price).fontSize(24).fontWeight(FontWeight.Bold).fontColor(this.brand())Text('颜色来自语义 token,主题变化时组件不用改。').fontSize(13).fontColor(this.textSecondary())Button(this.selectedPlan===plan?'当前方案':'选择方案').enabled(this.selectedPlan!==plan).backgroundColor(this.brand()).onClick(()=>this.selectedPlan=plan)}.alignItems(HorizontalAlign.Start).padding(14).backgroundColor(this.cardBg()).borderRadius(8)}build(){Column({space:14}){Row(){Text('主题预览').fontSize(22).fontWeight(FontWeight.Bold).fontColor(this.textPrimary())Blank()Toggle({type:ToggleType.Switch,isOn:this.darkMode}).onChange((value:boolean)=>this.darkMode=value)}.width('100%')this.PlanCard('专业版','¥129/月','pro')this.PlanCard('团队版','¥399/月','team')Button('删除试用数据').width('100%').backgroundColor(this.danger())}.padding(16).height('100%').backgroundColor(this.pageBg())}}

把关键代码一段段拆开

brand()danger()success()是语义入口。组件不需要知道浅色模式品牌色是哪个蓝,也不需要知道深色模式危险色该提亮多少,只要知道当前用途是品牌、危险还是成功。

pageBg()cardBg()分开很重要。暗色模式下如果页面和卡片都用同一个深色,卡片层级会消失,用户很难扫读内容。

PlanCard()里没有散写业务色值,只有 token 调用。真实项目可以把这些方法迁到主题对象或资源文件,页面代码基本不用动。

容易踩坑的点

  • blue1blue2命名,品牌色一换名字就失效。
  • 危险按钮复用品牌色,只靠文案表达删除风险。
  • 暗色模式只反转背景,没有调整辅助文字对比度。
  • 卡片背景和页面背景太接近,层级不清楚。
  • 同一个语义在不同页面写了不同色值,主题升级时漏改。

优化建议

颜色 token 不要一次性设计几十个。先从品牌、危险、成功、主文案、弱文案、页面背景、卡片背景开始,覆盖大多数页面后再补充分割线、遮罩、禁用态等细项。

深色模式不是简单把背景变黑。危险色、成功色、品牌色都要考虑可读性,尤其是小字号标签和弱提示文案。上线前建议在真实设备上看一遍亮度较低的场景,很多对比度问题在模拟器里不明显。

颜色 Token 要先分清语义

颜色 token 的重点不是少写几个#,而是让每个颜色有稳定角色。品牌色、危险色、成功色、主文案、辅助文案、页面背景和卡片背景,这些语义一旦稳定,主题切换就不会扩散到每个组件。

示例里的brand()danger()success()分别承担不同含义。删除按钮不能因为品牌色好看就继续用品牌色,成功提示也不应该和危险提示只靠文案区分。颜色语义越清楚,用户越容易理解状态。

写在最后

暗色模式尤其要注意层级。页面背景和卡片背景如果太接近,内容会糊成一片;辅助文字如果过暗,低亮度设备上会很难读。主题适配不是简单换一组色值,而是要保证信息层级仍然成立。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/12 20:05:09

桌面端 AI 自动化体验,OpenClaw 从安装到任务测试全流程

💡OpenClaw 桌面 AI 智能体|Windows/macOS 完整部署与问题排查 适配系统:Windows10/11 64 位、macOS 12 及以上✨ 当前版本:Windows v2.9.3 /macOS v2.7.9 现在很多人都想体验可以直接操作桌面文件、软件的 AI 智能体&#xff0…

作者头像 李华
网站建设 2026/8/12 20:04:25

JavaScript无限循环导致浏览器卡死的调试与解决方案

1. 从一次真实的“浏览器卡死”事故说起 那天下午,我正在为一个复杂的表单验证逻辑编写一个 while 循环。本意是遍历一个动态生成的数组,检查每个元素的状态。我自信满满地写下了 while (true) { ... } ,心想里面肯定有 break 条件。结…

作者头像 李华
网站建设 2026/8/12 20:03:49

Apache Doris BitMap去重实战:高基数场景下替代COUNT(DISTINCT)的性能优化方案

1. 从“计数不准”到“精准去重”的实战需求 在数据仓库和实时分析领域,我们经常遇到一个看似简单却暗藏玄机的问题:如何精确地统计一个集合中不重复元素的数量?尤其是在处理海量用户ID、设备ID、订单号等场景时,传统的 COUNT(DI…

作者头像 李华
网站建设 2026/8/12 20:02:27

科研课题查新报告可以加急办理吗?一般多久能拿到?

如果离申报截止日期只剩两三天,才突然想起科技查新报告还没办理, 或者突然接收到导师的临时通知要求科研课题查新报告,当下一点准备还没有。 遇到这些情况,应该怎么办呢?可以要求加急办理查新报告吗? 不慌…

作者头像 李华
网站建设 2026/8/12 19:59:27

.NET编码规范05-Roslyn分析器与StyleCop

.NET编码规范 第 5 篇:Roslyn 分析器与 StyleCop —— 代码质量与风格双保险 前言 如果 .editorconfig 是交通规则标识,那么 Roslyn 分析器就是 24 小时执勤的交警 —— 它在代码编写的瞬间就开始工作,实时检查你的代码是否合规。 本文重…

作者头像 李华
网站建设 2026/8/12 19:58:15

A-59F双尺度延迟架构:100ms回声尾对决15ms啸叫

一、背景与问题:本地扩声的啸叫与全双工回声是两类不同尺度的失真在导游讲解器、小蜜蜂喊话器、会议扩声这类"本地拾音—本地放音"的设备里,工程师面对的是两种性质迥异的失真。其一是声学反馈啸叫(howling)&#xff0c…

作者头像 李华