Strata 设计系统改造记录
把一套扁到没有区分度的界面,重做成「五级表面 + 八条色相轨道」的分层语言:样式仍然是一份 CSS,但每一块内容都重新有了位置。
目录
按章节顺序排列,点击直接跳转。
建议先浏览组件库 demo 页,再对照本文的分层与拆分思路阅读。
分层与色相
层次不是装饰,是结构:五级表面 + 一条独立凹槽层
改造的起点是一个很具体的不满:页面上的每一块内容看起来都一样重。 卡片、表格、引用、注释全是同一个灰底加一条边框,滚动时找不到断点, 读者只能靠标题字号勉强分辨段落。这是扁平化最常见的副作用 —— 层次被删掉之后,没有东西替它说话。
Strata 的答案是把层次做成可读的信息,而不是用装饰去补。 两件事:一是给表面分级,二是给区块上色。
表面分成五级 —— void / base / surface-1 /
surface-2 / surface-3,再外挂一个比页面更暗的
inset 凹槽层。所有结构都由明暗和 1px 发丝线承担,
静态面板一律不加投影 —— 边框和阴影同时出现,边界就糊了。
区块则各自拥有一条色相轨道,色相只出现在三个地方:等宽序号徽标、分区顶部的发丝线、 底色的柔和染色。相邻分区永不共享底色,所以滚动时每一段都有明确的入口和出口。
/* 语义 token —— 组件不直接引用原始色值 */html.strata-root { --base: #060b14; --surface-1: #0b111f; --surface-3: #161f33; --line: rgba(255,255,255,.09); --line-strong: rgba(255,255,255,.17); --accent: #3b82f6; /* 主色:蓝 */} /* 所有组件规则作用域在 .strata 内,0,1,1 稳压站点全局的 0,1,0 */.strata .btn { background: var(--accent); color: var(--accent-ink); }
- [*]band treatments6
- [*]section hues8
- [*]surface levels5 + inset
- [*]hairline weights3
- [*]hovercolour swap, no tween
“扁平不是把层次删掉,而是把层次画得更准确。发丝线就够了,不必再加一道阴影。”
组件拆分
30 个组件,四层职责,同一套类名契约
按区块边界拆成 30 个组件:基础组件负责视觉,交互组件负责行为, 全部通过 props 暴露配置项,并沿用同一套类名契约,避免正文样式塌陷。
- 表面层:Panel / Card / StatCard / GlassTable / ListGroup
- 结构层:Band / SectionHeading / SpecList / Divider / KeyCap
- 交互层:Modal / Toast / Tooltip / Dropdown / Tabs / SearchBox
- 反馈层:Alert / Progress / Spinner / Skeleton / Empty / StatusIndicator
- 骨架层:ArticleShell / ArticlePart / Sidebar / EdgeRail
交互运行时
一次事件委托,全部由属性声明驱动
页面上不需要手写任何 JS:打开弹窗、弹 toast、切换下拉、复制代码、排序表格,
全部靠 data-strata-* 属性声明,运行时在 document 上做一次事件委托。
键盘语义是完整的 —— 弹窗焦点圈闭、Esc 关闭并还焦、tablist 方向键漫游、命令面板 ↑↓ 选择。
<!-- 交互靠 data-strata-* 属性声明,页面不写一行 JS --><Button data-strata-open="confirmModal">打开弹窗</Button><Button data-strata-toast="已保存">保存</Button><CodeBlock code="npm i" /> <!-- 复制按钮自动就位 --> <!-- 打字机 / 数字滚动 / 滚动揭示同样是属性驱动 --><span data-strata-type data-words='["A","B"]'>A</span><span data-strata-count="128">0</span><div class="pg-reveal">进入视口时淡入</div>
明暗主题
只换一组语义 token,组件里没有 dark: 变体
主题只改一组语义 token,组件内部一个 dark: 变体都没有。
暗色是默认,选择写入 localStorage,
并由一段放在样式表之前的内联脚本恢复 —— 所以刷新时不会闪白。
想直接分享某个主题,加一个 ?mode=light 就行。
切换的瞬间会挂上 260ms 的整体淡变:只过渡颜色类属性, 位移动画与「悬停不补间颜色」的规则都不受影响。
整套系统最后压进 2.1kb 的 CSS(gzip)。真正让它「不糊」的不是新组件, 而是那些看起来很琐碎的决定:三层发丝线、六个底色、八条色相, 以及一条不肯让步的规则 —— 悬停只换色,不做过渡。