
字节笔记本
2026年10月6日 · 约 4 分钟读完
DeepSeek Harness 的 Web 样式系统约定
DeepSeek Harness 的浏览器客户端在样式上执行一套集中管理的约定:主题 token 由专门的包统一维护,功能组件只负责消费,不允许各自为政。这套约定明确了职责归属、组件书写规则和变更流程。本文把其中的要点整理出来,也给想在自家项目里落地设计 token 体系的团队一个可参照的样本。
职责怎么分
整套体系围绕两个基础包展开。ui-theme 是主题包,负责静态色阶(以 --dsw- 前缀命名)、语义别名、排版、动效、渐变、阴影、滚动条样式,以及明暗主题偏好;全局样式表也归它所有,token 值由源码生成清单,约定本身不重复罗列。ui-layout 则负责把解析后的主题快照应用到文档上,让页面真正吃到主题。
功能包处在消费端:只允许使用 --dsw-alias-* 语义别名,不得另行定义全局主题,也不得复制静态色板值。换句话说,颜色、排版、层级、动效这些共享值只有一个出处,就是主题包。

组件层面的边界同样清晰。组件样式以 CSS Modules 的形式放在组件旁边;当某个值只属于该组件自己的布局或呈现约定时,组件可以定义局部自定义属性。共享的东西上收,局部的东西下放,这是整套约定的核心思路。
组件规则清单
具体到每个功能组件,约定给出了硬性规则:
- 用 CSS Modules 和 clsx 组合类名,不引入组件库,也不用 Tailwind。
- 功能组件只使用语义别名 token,不得复制静态色板值,也不得在 CSS 里写颜色字面量。
- 组件 CSS 不得包含主题选择器,明暗主题的覆盖逻辑由主题所有方统一处理。
- 字体大小必须与行高配对出现,已有排版角色匹配时直接使用主题排版变量。
- 源码文本、终端输出和 diff 行在需要保留列结构时不换行;滚动条使用共享样式,不得为组件单独定义滚动条选择器。
- 呈现规则写在 CSS 里;React 内联样式只允许传递组件局部自定义属性的值,不得在行内编码主题分支。
- 新增过渡动画或仅悬停可见的控件时,必须保留清晰可见的键盘焦点,并遵守减少动态效果的行为。

这些规则大多有明确动机:语义别名让换主题、调色板时只改一处;字号配行高避免排版漂移;共享滚动条防止同一页面出现多种滚动手感;键盘焦点和减少动效则守住可访问性底线,保证键盘用户和对动画敏感的用户不被落下。
变更怎么走
需要新增或修改共享 token 时,先在所属的 ui-theme 样式表里改,然后在功能包中使用它的语义别名,而不是绕过主题直接写值。公共样式约定发生变化时,还要同步更新所属包的参考文档,保持文档与实现一致。视觉行为则纳入统一的测试策略约束,避免改动样式时悄悄破坏既有表现。
值得借鉴的三点
即使不使用这套代码库,这些约定也能迁移到多数前端项目:
- token 单一出处。颜色、字号、动效只在一个包里定义,其他地方一律消费别名,主题切换和全局调色才有抓手。
- 组件样式就地存放。CSS Modules 跟着组件走,配合 clsx 处理条件类名,比全局样式表或重型组件库更可控。
- 把可访问性写进规则。键盘焦点可见、尊重减少动效偏好,这类要求只有变成硬性约定,才不会在快速迭代中被牺牲。
对维护者来说,这套约定把「样式该写在哪、值该从哪来」变成有章可循的问题;对使用者来说,读代码时也能更快定位主题相关的改动点。



