← 目录 07 / 11

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 动效的三个硬约束

  1. 静止态必须是默认样式,动效只做增强。 如果初始位移写在 @keyframes 的 from 里,用户在 prefers-reduced-motion 下关掉动画后会卡在屏幕外。
  2. prefers-reduced-motion 下显式复位 opacity 与 transform,只写 animation: none 不够。
  3. 转场结束后必须验证元素归位(见 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;页面转场单独开令牌;静止态即默认态
无障碍:焦点环自己设计(浅底深环/深底浅环);不靠颜色单独传达信息