为什么不是「再描一层边」
暗色界面最常见的层级手段是「加一条边框」或者「再叠一层更亮的灰」。 两条路短期都有效,但用多了会出现同一个问题: 边界越来越多,可信息并没有变多。
Ember 的取舍是:把层级交给材质而不是描边数量。 凹槽靠内阴影,凸起靠外部投影加上缘高光 —— 光线恒定来自顶部,所以「哪个在上面」是一眼可读的。
四级材质
整套系统只有四种材质,其余都是它们的组合与再利用:
carveinset 0 2px 5px
raise0 1px 2px + 高光
deepinset 0 8px 20px
- carve 凹槽:输入、轨道、次级操作
- raise 微凸:按钮、徽章、激活态
- deep 深雕:日志、代码、运行上下文
- well 浅井:统计数值、表格、引用块
浅井是我最喜欢的一级:它足够浅,不会把卡片切成两层, 但又足够明确,让数字「沉进去」而不是「浮在表面」。
噪点分档
磨砂质感来自 feTurbulence 噪点,但全页同一种颗粒会显得廉价 —— 真实材质的颗粒是随尺度变化的。
Ember 用三档频率(.85 / .65 / .4),并按元素细分强度: 大面积表面弱(0.15)、控件中等(0.34)、小徽标强(0.42)。 三种颗粒叠加时用不同的平铺尺寸,避免看出重复图案。
噪点不是为了「看起来旧」,而是为了让大面积的纯色不再像一块塑料板。
刻槽透光
消息提示与引用块的左侧,最初是一条实色竖线 —— 太平庸,也不符合这套语言。改成凿出一道内凹刻槽:
- 槽左缘深阴影、右缘一道反光切线,模拟被凿开的断面
- 语义色不涂在表面,而是从槽内透出微光
- 成功绿、警告黄、危险红各自不同,引用块用暖橙
结果是:颜色有了「深度」,而不是贴在边缘的一层油漆。
令牌清单
整套系统对外只暴露这些令牌,改一处即全站生效:
--carve inset 0 2px 5px / .9
--deep inset 0 8px 20px / .9
--raise 0 1px 2px + inset highlight
--well inset 0 1px 3px / .5
--hair 0 1px 0 rgba(255,255,255,.05)
--glow 0 0 12px rgb(217 95 39 / .55)
--grain-surface .15
--grain-control .34
--grain-chip .42
这套语言没有引入任何依赖:材质是 box-shadow,噪点是内联 SVG, 动效只做位移与透明度。它可以在任意 Astro 页面里被完整复制。