07 · 设计规则速查
本文件只记录能跨项目复用的规则与数值。具体到「构成主义」这一风格的美学考据在
01-美学谱系与形式法则.md,实现配方在04-技术实现手册.md。 全目录导航见README.md。 所有对比度都是 WCAG 2.x 相对亮度公式精算值,不是目测。
1. 色彩纪律
1.1 先算,再选色
规则:任何前景/背景配对,在写进 CSS 之前先算对比度。 目测在深色和低饱和色上极不可靠。
判定线(WCAG 2.1 AA):
| 用途 | 最低对比度 |
|---|---|
| 正文(< 24px 或 < 18.66px 粗体) | 4.5 : 1 |
| 大字(≥ 24px 或 ≥ 18.66px 粗体) | 3 : 1 |
| 非文本(图标、控件边界、图形) | 3 : 1 |
可复制的计算器(PowerShell,无依赖):
function Lum([string]$hex){
$hex=$hex.TrimStart('#')
$v=@(0,2,4)|ForEach-Object{
$c=[Convert]::ToInt32($hex.Substring($_,2),16)/255.0
if($c -le 0.03928){$c/12.92}else{[Math]::Pow((($c+0.055)/1.055),2.4)}
}
0.2126*$v[0]+0.7152*$v[1]+0.0722*$v[2]
}
function Ratio([string]$a,[string]$b){
$la=Lum $a; $lb=Lum $b
$hi=[Math]::Max($la,$lb); $lo=[Math]::Min($la,$lb)
[Math]::Round((($hi+0.05)/($lo+0.05)),2)
}
Ratio '#cc0000' '#f2e8d5' # → 4.84
1.2 反直觉的实测结论(都很容易被"看起来还行"骗过)
| 配对 | 对比度 | 说明 |
|---|---|---|
#cc0000 苏维埃红 on #f2e8d5 泛黄纸 |
4.84 | ✅ 过 AA 正文线 —— 深红在暖底上比直觉更好 |
#D6281F 朱红 on #EFE9DC 米黄纸 |
4.15 | ⚠️ 仅大字。看起来更亮反而更差 |
#FF0000 纯红 on 白 |
4.00 | ❌ 连 AA 大字都过不了(大字要 3:1,它过了;但正文不过) |
#cc0000 红 on #1a1a1a 纯黑 |
2.96 | ❌ 禁止在黑底上用红字 |
#d4a843 金星 on 纸 |
1.82 | ❌ 完全不能承载文字,只能做图形 |
#d4a843 金星 on 纯黑 |
7.86 | ✅ 同样一枚金色,换底就翻盘 |
#8b4513 棕 on 纸 |
5.84 | ✅ |
#8b4513 棕 on 纯黑 |
2.45 | ❌ |
#8E1B14 暗红 on 纯黑 |
2.79 | ❌ 看起来"够深",实际任何字号都不合格 |
结论:同一个颜色在不同底色上的可用性可以完全反转。必须逐对计算,不能给颜色本身打标签。
1.3 强调色的面积预算
强调色占画面 5–15%,不是 50%。 超出这个范围,强调色就不再是强调,而且会挤掉底色承载文字的能力。
| 角色 | 面积 | 说明 |
|---|---|---|
| 底色 | 60–75% | 可读性的地基 |
| 主结构色(墨/深灰) | 20–30% | 正文、分隔、压重 |
| 强调色 | 5–15% | 只出现在最关键的 1–2 处 |
| 点缀色 | 0–3% | 可选,用于破局 |
1.4 焦点环必须自己设计
outline 的默认值在深色/彩色底上经常不可见。浅底用深色环、深底用浅色环,或用双轨:
:focus-visible { outline: 4px solid var(--ink); outline-offset: 3px; }
.on-dark:focus-visible { outline-color: var(--paper); }
不要依赖"颜色变化"来传达状态(色盲 + 强制色模式会吞掉它)。
2. 尺寸与密度
| 项 | 阈值 | 理由 |
|---|---|---|
| 正文起始字号 | 16–18px | 低于 16px 在移动端要捏合 |
| 触控目标 | ≥ 44 × 44px | 写进 min-height,别靠 padding 碰运气 |
| 标题 : 正文 字号比 | 普通 2.5–3 : 1;要冲击力则 ≥ 6 : 1 | 比例决定"气质",不是字号绝对值 |
| 长文行宽 | 60–75 ch |
ch 对中文约等于半个字宽 |
| 行高 | 标题 0.8–1.0,正文 1.5–1.75 | 标题紧、正文松 |
| 大标题字距 | 负值(-0.02 ~ -0.05em) | 字号越大越要收紧 |
| 小标签字距 | 正值(0.12 ~ 0.22em) | 小字不放开就挤成一团 |
3. 质感与纹理的强度上限
纹理很容易做过。判断阈值:把页面缩到 50% 看 —— 如果纹理依然明显,就是太重了。
| 效果 | 强度上限 |
|---|---|
纸张颗粒(feTurbulence) |
opacity 0.04 – 0.08 |
| 半调网点 | 网点间距 3 – 6px(< 3px 高分屏摩尔纹;> 6px 变装饰画) |
| 纹理层 | 必须 pointer-events: none,且在正文之下 |
| 阴影 | 硬阴影模糊值恒 0;柔和阴影才用 blur |
4. 形状与阴影
/* 零圆角体系里的"硬阴影":模糊值必须是 0 */
--shadow-hard: 4px 4px 0 0 var(--ink);
/* 底部抽屉的"悬浮":抬升带不能用单一颜色 ——
如果抬升带和背后的内容同色,等于没有。至少一层用对比色。 */
box-shadow:
0 -5px 0 0 var(--red), /* 贴边棱:风格色 */
0 -17px 0 0 var(--ink); /* 外层:无论背后是什么颜色都读得出来 */
斜向体系要统一一个角度:全站一个 --tilt,不要每块换角度(每块换角度看起来是"随机歪了"而不是"设计过")。
5. 动效
5.1 机械语汇(缺省规则)
--ease-mech: linear; /* 不要 ease-in-out:那是最没有性格的缓动 */
--dur-fast: 75ms; /* hover / active */
--dur-base: 100ms; /* 状态切换 */
这组值对"硬边、机械"的风格成立,对"柔和、呼吸感"的风格不成立。 后者需要更长的时长和缓动曲线。
5.2 页面转场是例外,要单独开令牌
页面级转场需要的时长比微交互长一个量级(否则只是"闪一下")。不要复用微交互的令牌,单独开:
--dur-curtain: 280ms;
--ease-curtain: cubic-bezier(.85, 0, .15, 1); /* 前快后慢,不是 ease-in-out */
隔离好处:换风格时改一处,不会连带影响所有 hover。
5.3 动效的三个硬约束
- 静止态必须是默认样式,动效只做增强。 如果初始位移写在
@keyframes的from里,用户在prefers-reduced-motion下关掉动画后会卡在屏幕外。 prefers-reduced-motion下显式复位opacity与transform,只写animation: none不够。- 转场结束后必须验证元素归位(见
04-验证工作流.md的"擦除层归位"检查)—— 否则会有一层东西永久盖在页面上。
6. 字体
| 决策 | 规则 |
|---|---|
| 中英混排 | 西文在前、中文在后(font-family: "Oswald", "Noto Sans SC", ...) |
| 字重对齐 | 中西文字重不能直接照抄数值 —— 视觉重量差很大,要单独调 |
| 兜底 | 中文全量字体有数 MB,必须 unicode-range 分包(Google Fonts 自动做,自托管要手动) |
| 大写 | 用 text-transform: uppercase 做视觉大写,不要写进 DOM —— 否则部分读屏软件逐字母朗读 |
| 小 caps | 只在字体真有 small-caps 字形时用 font-variant-caps: all-small-caps;否则浏览器伪造成缩小的大写,很难看 |
| 西里尔/多语种 | 不要凭字体气质猜覆盖范围,要实测(见 04-验证工作流.md 第 5 节的 cmap / subsets 判定方法) |
7. 一份可直接用的规则速查(贴墙版)
颜色:先算对比度 → 正文 ≥4.5:1、大字 ≥3:1;强调色面积 5–15%
字体:正文 ≥16px;标题:正文 要冲击就 ≥6:1;大写写在 CSS 不写 DOM
尺寸:触控 ≥44px;行宽 60–75ch
质感:颗粒 0.04–0.08;网点 3–6px;纹理层放正文之下 + pointer-events:none
形状:硬阴影 blur 恒 0;全站统一一个斜角
动效:微交互 linear 75/100ms;页面转场单独开令牌;静止态即默认态
无障碍:焦点环自己设计(浅底深环/深底浅环);不靠颜色单独传达信息