构成主义设计系统规格 v0.1
这是一份可直接翻译成 CSS 变量的规格书。所有色值都经过 WCAG 对比度实测,所有字体都经过西里尔覆盖核实——不是凭感觉挑的。 实测方法与版本见文末"数据来源与验证状态"。
1. 色彩系统
1.1 设计前提
构成主义海报是双色油墨印在廉价纸上:纸本身是米黄偏灰的(不是纯白),墨只有黑和红。所以色板要以"纸"为基准,而不是以"白"为基准。
面积配比是硬约束(这是最容易做错的地方):
| 颜色 | 面积占比 | 角色 |
|---|---|---|
| 纸(米黄) | 60–75% | 基底,呼吸,可读性保障 |
| 墨黑 | 20–30% | 结构、正文、分隔、压重 |
| 朱红 | 5–15% | 引爆点。只出现在最关键的一两处 |
| 蓝 / 黄(至上主义点缀) | 0–3% | 可选。用于单调处破局,不可参与主结构 |
1.2 色板令牌(含实测对比度)
:root {
/* ---- 纸 ---- */
--kv-paper: #EFE9DC; /* 主纸色:廉价胶版纸 */
--kv-paper-dim: #E3DBC9; /* 纸的暗面:分层、凹陷、次级区块 */
--kv-paper-lift: #F7F3EA; /* 纸的亮面:极少量用于提升 */
/* ---- 墨 ---- */
--kv-ink: #12100E; /* 油墨黑(不用纯黑 #000,纯黑太屏幕感) */
--kv-ink-soft: #3A352E; /* 次级文字 */
--kv-rule: #12100E; /* 分隔线用纯墨,1–6px 粗线 */
/* ---- 朱红(两个变体,用途不同!见下表) ---- */
--kv-red: #D6281F; /* 印刷朱红 —— 图形/大面积/大字号 */
--kv-red-ink: #B31B12; /* 深红 —— 小字号文字专用(通过 AA) */
--kv-red-deep: #8E1B14; /* 圧印/阴影/套印底层 */
/* ---- 至上主义点缀(慎用) ---- */
--kv-blue: #16407A;
--kv-yellow: #E8B31A;
/* ---- 半调/网点灰 ---- */
--kv-gray: #8A8377;
}
1.3 实测对比度与使用授权(这是本节最重要的表)
用 WCAG 2.x 相对亮度公式精算(脚本见 04-技术实现手册.md):
| 前景 | 背景 | 对比度 | 结论 |
|---|---|---|---|
--kv-ink 墨黑 |
--kv-paper 纸 |
15.69 : 1 | ✅ AA 正文可用 |
--kv-paper 纸 |
--kv-ink 墨底 |
15.69 : 1 | ✅ AA 正文可用 |
--kv-yellow 黄 |
--kv-ink 墨底 |
9.85 : 1 | ✅ AA 正文可用 |
--kv-blue 蓝 |
--kv-paper 纸 |
8.47 : 1 | ✅ AA 正文可用 |
--kv-red-ink 深红 |
--kv-paper 纸 |
5.63 : 1 | ✅ AA 正文可用 |
--kv-paper 纸 |
--kv-red-ink 深红底 |
5.63 : 1 | ✅ AA 正文可用 |
--kv-red 朱红 |
--kv-paper 纸 |
4.15 : 1 | ⚠️ 仅 ≥24px 或 ≥18.66px 粗体 |
--kv-paper 纸 |
--kv-red 朱红底 |
4.15 : 1 | ⚠️ 仅 ≥24px 或 ≥18.66px 粗体 |
--kv-red 朱红 |
--kv-ink 墨底 |
3.78 : 1 | ⚠️ 仅大字 |
--kv-gray 灰 |
--kv-paper 纸 |
3.10 : 1 | ⚠️ 仅大字 / 装饰性 |
--kv-red-deep 暗红 |
--kv-ink 墨底 |
2.79 : 1 | ❌ 任何字号都不合格,禁止使用 |
由此得出的硬规则:
- 需要正文字号的红字 → 必须用
--kv-red-ink(#B31B12),不能用--kv-red。 - 朱红
--kv-red只用于:大面积色块、几何图形、≥24px 的标题。 - 灰
--kv-gray只能做装饰性网点/网纹,不能承载文字。 --kv-red-deep禁止出现在墨底上(这条是精算才发现的坑)。- 不要用
opacity制造"浅色文字"——那会绕过上面的全部结论。需要浅色就加色板令牌。 - 🔴 绝对不要用纯红
#FF0000做白底正文:它在白底只有 4.00 : 1,连 AA 正常字号都不过。这是最常见的"看起来够红"的错误用色。
替代方案:如果你希望"红色只有一枚、且正文字号也能用",可以用印刷油墨红 #C8102E(在白底上 5.88 : 1,过 AA 正文)。它的饱和度比朱红略低,但一次解决所有字号问题:
/* 单红方案(牺牲一点"朱红感",换来全字号合规) */
--kv-red: #C8102E; /* 5.88:1 on #fff,图形与大字 */
--kv-red-ink: #C8102E; /* 同一枚,正文也能用 */
另一种更沉的印刷红:#AD2A07(白底 6.75 : 1,是白底上最优的红)。代价是偏砖红,离"苏联海报朱红"远了一点。
1.4 深色模式(可选)
构成主义没有"深色模式"这个概念。如果必须做,应该理解成"反相印刷":墨色当纸、纸色当墨,红色保持不变(但红底白字同样受 4.15:1 限制)。
2. 字体系统
2.1 选字原则
构成主义的字体气质:窄、重、几何、全大写、工业怪诞体(grotesque)。当年用的是木活字和手工铅字,特征是字面窄、笔画均匀、无衬线、字距可压到极紧。
2.2 西里尔(Cyrillic)覆盖核实结果 ⚠️
这是本次调研最有价值的发现之一。 很多设计稿惯用的"海报字体"其实不支持西里尔字母,如果页面要出现俄文(构成主义主题下很常见)会直接掉字体。
数据来源:Google Fonts 官方元数据 fonts.google.com/metadata/fonts(共 1950 个字族)。
✅ 支持西里尔(可放心用):
| 字体 | 类别 | 字重轴 | 气质 | 建议角色 |
|---|---|---|---|---|
| Oswald | Sans | 200–700 | 窄体工业怪诞体,最贴近构成主义铅字 | 主力标题(全大写) |
| Unbounded | Sans | 200–900 可变 | 几何、方正、当代感、有先锋气 | Hero 超大标题(次选主力) |
| Russo One | Sans | 400 | 极粗、方正、机械 | 单字重标题、Logo |
| Rubik Mono One | Sans | 400 | 等宽超粗,块状 | 数据/编号/印章式文字 |
| Jost | Sans | 100–900 + 斜体 | 几何无衬线,Futura 的免费近亲(Futura 正是构成主义时期的产物) | 副标题、几何感正文 |
| Play | Sans | 400/700 | 方正、略窄 | 次级标题 |
| PT Sans / PT Serif / PT Mono | Sans/Serif/Mono | 各 400/700 | 俄罗斯本土设计(ParaType),与主题同源 | 正文、注释 |
| Roboto Condensed | Sans | 100–900 + 斜体 | 窄体、中性偏工业 | 大段窄栏正文 |
| Alumni Sans | Sans | 100–900 + 斜体 | 极窄、高瘦 | 超大单行标题、竖排 |
| Manrope / Onest / Golos Text / Commissioner | Sans | 200–900 可变 | 当代几何,可选正文 | 正文(需要现代感时) |
| Noto Sans / Noto Serif / Source Serif 4 | Sans/Serif | 可变 | 覆盖面最广,兜底 | 兜底与长文 |
| Yeseva One / Prata / Podkova / Oranienbaum | Display/Serif | — | 俄式装饰衬线 | 反差点缀(非主用) |
| Ruslan Display / Prosto One / Kelly Slab / Iceberg / Marmelad | Display | — | 俄式装饰/粗黑 | 极少量点缀 |
❌ 不支持西里尔(页面出现俄文会掉字体):
Anton、Bebas Neue、Archivo、Archivo Black、Barlow、Barlow Condensed、Bricolage Grotesque、Chivo、Space Grotesk、Syne、Teko、Saira Condensed、Fjalla One(无基础西里尔)
其中 Anton / Bebas Neue / Archivo Black / Barlow Condensed 是最容易被设计师顺手拿去做"海报标题"的四个——如果确定不需要俄文可以用,但只要有一处俄文就会露馅。
2.3 中文选字(已核实许可证)
| 字体 | 仓库 | Star | 许可证 | 用途 |
|---|---|---|---|---|
| 得意黑 Smiley Sans | atelier-anchor/smiley-sans |
14,905 | OFL-1.1 | ⭐ 中文标题首选——窄体+斜体骨架,气质与构成主义高度契合,是中文里少见的"海报字" |
| 霞鹜文楷 LXGW WenKai | lxgw/LxgwWenKai |
26,243 | OFL-1.1 | 正文/引文(楷体,气质偏温,做对比用) |
| 思源黑体 Source Han Sans | adobe-fonts/source-han-sans |
17,331 | OFL-1.1(仓库标注 NOASSERTION,实为 OFL) | 中文正文兜底,多字重 |
| Noto CJK | notofonts/noto-cjk |
4,093 | OFL-1.1 | 兜底 |
2.4 推荐字体栈(三套,按场景选)
/* A 套:默认(中英混排,最稳) */
--kv-font-display: "Oswald", "得意黑 Smiley Sans", "Noto Sans SC", sans-serif;
--kv-font-body: "PT Sans", "Noto Sans SC", "Source Han Sans SC", sans-serif;
--kv-font-mono: "JetBrains Mono", "PT Mono", ui-monospace, monospace;
/* B 套:更当代、更"先锋派"(几何感更强) */
--kv-font-display: "Unbounded", "得意黑 Smiley Sans", sans-serif;
--kv-font-body: "Jost", "Noto Sans SC", sans-serif;
--kv-font-mono: "IBM Plex Mono", "PT Mono", monospace;
/* C 套:更贴近"俄罗斯印刷所"(同源感强) */
--kv-font-display: "Russo One", "Oswald", "得意黑 Smiley Sans", sans-serif;
--kv-font-body: "PT Serif", "Noto Serif SC", serif;
--kv-font-mono: "PT Mono", monospace;
中文必须放在西文之后,且中文标题要用
font-weight与西文的视觉重量对齐(Oswald 700 ≈ 思源黑体 Heavy ≈ 得意黑只有一个字重但字面重)。
2.5 字号与排版参数
核心是极端对比。 标题:正文 ≥ 6:1(瑞士风格约 2.5–3:1)。
:root {
/* 阶梯(fluid,基于 clamp) */
--kv-size-mega: clamp(4rem, 15vw, 16rem); /* Hero 单字/单词,占满屏宽 */
--kv-size-h1: clamp(2.75rem, 8vw, 7rem); /* 章节主标题 */
--kv-size-h2: clamp(1.75rem, 3.6vw, 3rem);
--kv-size-h3: clamp(1.25rem, 2vw, 1.75rem);
--kv-size-body: clamp(1rem, 1.05vw, 1.125rem); /* 16–18px 起 */
--kv-size-label: 0.75rem; /* 标签/编号,全大写+宽字距 */
--kv-size-quote: clamp(1.5rem, 3vw, 2.5rem);
/* 字距:大标题收紧,小标签放开 —— 这是构成主义的"呼吸" */
--kv-track-mega: -0.04em;
--kv-track-h: -0.02em;
--kv-track-body: 0;
--kv-track-label: 0.18em; /* 小字必须放开,否则挤成一团 */
/* 行高:标题极紧,正文正常 */
--kv-leading-mega: 0.82;
--kv-leading-h: 0.95;
--kv-leading-body: 1.55;
/* 字重 */
--kv-weight-display: 700;
--kv-weight-body: 400;
--kv-weight-label: 600;
}
排版硬规则:
1. 标题一律全大写(text-transform: uppercase)——西文。中文不做强制大写,改用字重+字距。
2. 标题永远 text-wrap: balance,正文 text-wrap: pretty。
3. 斜排只允许短标签/短标题(≤ 3 个词),正文永远水平。原因见无障碍一节。
4. 数字用 font-variant-numeric: tabular-nums,编号列要对齐。
3. 网格与间距
3.1 网格
12 栏 + 可见轴线,但允许被冲破。
:root {
--kv-cols: 12;
--kv-gutter: 1.5rem; /* 栏间距 */
--kv-margin: clamp(1rem, 4vw, 4rem); /* 页边距 */
--kv-hairline: 1px; /* 细线/网格线 */
--kv-rule: 6px; /* 粗分隔线(构成主义特征) */
--kv-axis-angle: -15deg; /* 主斜轴角度,全站统一 */
}
用法规则:
- 内容区默认占 1–7 栏(不对称),不要居中。居中=瑞士风格。
- 每页/每屏至少有一处跨满 12 栏的元素(贯穿式色块或斜轴)。
- 网格线可以显示出来(用 repeating-linear-gradient 做底纹,透明度 6–10%)。
- 全局 --kv-axis-angle 是"主梁"角度,全站统一一个角度,不要每块换角度——否则会散。
3.2 间距阶梯
8pt 基准,但构成主义偏爱突兀的大间距 + 紧密的小间距并存(对比原则在空间上同样成立)。
:root {
--kv-space-1: 0.25rem; /* 4 */
--kv-space-2: 0.5rem; /* 8 */
--kv-space-3: 1rem; /* 16 */
--kv-space-4: 1.5rem; /* 24 */
--kv-space-5: 2.5rem; /* 40 */
--kv-space-6: 4rem; /* 64 */
--kv-space-7: 7rem; /* 112 */
--kv-space-8: 12rem; /* 192 — 用于制造"空"的冲击 */
}
4. 形状、边线与阴影
:root {
--kv-radius: 0; /* 全局零圆角,不可协商 */
--kv-border: 2px solid var(--kv-ink);
--kv-border-thick: 6px solid var(--kv-ink);
/* 只有两种"阴影",都不是柔和投影 */
--kv-shadow-hard: 8px 8px 0 var(--kv-ink); /* 硬边偏移(拟印刷/拟立体) */
--kv-shadow-red: 8px 8px 0 var(--kv-red); /* 红色硬边,克制使用 */
}
禁止清单:border-radius、box-shadow 模糊值(blur > 0)、linear-gradient 装饰性渐变、backdrop-filter 毛玻璃。
允许的例外:drop-shadow() 用于 SVG 几何形(保持硬边),mix-blend-mode 用于叠印。
5. 质感系统("印刷感"三件套)
必须极轻。目标是"这是印出来的",不是"这是做旧滤镜"。
| 效果 | 手段 | 强度上限 |
|---|---|---|
| 纸张纤维颗粒 | SVG feTurbulence 内联 data-URI 背景 |
opacity: 0.04–0.08 |
| 半调网点 | SVG pattern / radial-gradient 重复 / mask |
网点尺寸 3–6px,只在图片上 |
| 套印错位 | 伪元素复制文字,偏移 1–3px,mix-blend-mode: multiply |
偏移 ≤ 3px |
阈值判断:把页面缩到 50% 看——如果颗粒/网点依然明显,就是太重了;正确的强度是缩小时几乎看不见、原尺寸下能感觉到"不干净"。
6. 动效系统
:root {
--kv-ease-mech: cubic-bezier(0.85, 0, 0.15, 1); /* 机械、果断 */
--kv-dur-fast: 120ms;
--kv-dur-base: 200ms;
--kv-dur-slow: 320ms;
}
动效语汇(只允许这几种):
| 动作 | 说明 |
|---|---|
| 硬切入场 | 元素从侧向/斜向平移进入,无淡入,或淡入极快 |
| 裁切框扫过 | clip-path 从 0 到 100% 揭示图片 |
| 逐行跳出 | 标题按行 stagger 出现,每行延迟 40–60ms |
| 色块翻转 | 背景色在 hover 时硬切(无过渡或极短过渡) |
| 编号跳变 | 数字直接替换,不做滚动计数 |
禁止:弹性/回弹缓动、视差滚动叠加多层、超过 400ms 的动画、任何 ease-in-out 默认缓动。
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
7. 无障碍红线(这套风格的固有风险)
| 风险 | 具体问题 | 对策 |
|---|---|---|
| 斜排文字 | 旋转后的文字对屏幕阅读器无影响(DOM 顺序不变),但视觉阅读效率大幅下降,且长文本旋转后行宽变化导致难读 | 斜排只用于 ≤3 词短标签;正文永远水平 |
| 红字对比度 | 朱红在纸上仅 4.15:1,小字不合格 | 小字红用 --kv-red-ink |
| 极端字号 | clamp(..., 15vw, ...) 在窄屏可能溢出 |
必须配 overflow-wrap: anywhere + 容器 overflow: clip |
| 全大写 | 屏幕阅读器对全大写词的朗读可能逐字母拼读 | 用 text-transform: uppercase(视觉大写,DOM 保持正常大小写),不要在 HTML 里直接写全大写 |
| 质感叠加 | 颗粒/网点降低文字清晰度 | 质感层加 pointer-events: none 且不得覆盖正文区域 |
| 动效 | 硬切+闪动可能触发前庭不适 | 遵守 prefers-reduced-motion |
| 零圆角按钮 | 触控目标易过小 | 触控目标 ≥ 44×44px |
8. 现行规则来源:StyleKit「构成主义 Constructivism」
状态:由用户提供并声明已实际抓取确认(本环境搜索接口当时限流,未由我二次核验原文,故记为「用户实测来源」而非「我实测来源」)。
本位规则优先于本文档前面章节中的自拟取值。下表是 StyleKit 规则与它的落地结果:
| StyleKit 规则 | 取值 | 落地位置 | 精算结论 |
|---|---|---|---|
| 苏维埃红 | #cc0000 |
--red |
on 纸 4.84:1 —— 过 AA 正文线,比自拟的 #D6281F(4.15,仅大字)更合规 |
| 纯黑 | #1a1a1a |
--ink |
on 纸 14.32:1 |
| 泛黄纸 | #f2e8d5 |
--paper |
基准底色 |
| 金星 | #d4a843 |
--gold |
⚠️ on 纸仅 1.82:1 → 只能做图形;on 黑 7.86:1 可做文字 |
| 棕 | #8b4513 |
--brown |
on 纸 5.84:1 ✅;⚠️ on 黑 2.45:1 禁用 |
rounded-none |
硬直角 | 全局 border-radius: 0 |
— |
shadow-[4px_4px_0] |
版画硬阴影 | --shadow-hard: 4px 4px 0 0 var(--ink) |
模糊值恒为 0 |
对角倾斜 -rotate-6 / skew-x-3 |
-6deg / 3deg |
--tilt / --skew |
全站统一一个角度 |
font-black uppercase |
900 + 全大写 | 巨型标题改用 Unbounded 900 | Oswald 最重只有 700,没有真 900 |
| Mechanical Easing | 只准 linear + 75ms/100ms,禁 ease-in-out |
--ease-mech: linear,--dur-fast: 75ms,其余 100ms |
微交互全部合规;页面转场为有意例外(见下) |
| Block Invasion | 黑块从左横扫 | 曾实装为 .wipe 的 translateX 100ms linear |
⚠️ 已按要求回退,见下 |
StyleKit 动效语汇的落地状态:
| 语汇 | 本项目实现 | 状态 |
|---|---|---|
| Diagonal Aggression | 报纸板块与文章侧栏卡片:translate(-4px,-4px) skewX(-3deg) + 硬阴影同步拉开 |
✅ 采用 |
| Soviet Reversal | 板块 :active 变墨底纸字;文章条 :active 翻成纸底黑字 |
✅ 采用 |
| Mechanical Easing | 微交互 linear + 75/100ms |
✅ 采用 |
| Block Invasion | 曾实装为黑块从左横扫(translateX,100ms linear) |
⚠️ 已回退——用户认为此前的「红色幕布下坠」更有力量,故改回 |
有意偏离记录(用户决定):页面转场用 红色幕布下坠 —— 满屏
--red的clip-path自上而下压满 → 换视图 → 再向下收拢退场, 280ms +cubic-bezier(.85, 0, .15, 1)。 这偏离了 StyleKit「只准 linear + 75/100ms」的规则,影响范围仅.wipe一处, 其余所有过渡仍严格走 Mechanical Easing。 缓动值不是ease-in-out(规则明令禁止的那个),而是一条前快后慢的机械曲线。 2026-10-13 实测:真实动画路径端到端 6/6 通过,幕布退场后正确归位为polygon(0px 0%, 100% 0%, 100% 0%, 0px 0%)(零面积,不会卡在屏幕上)。
从这套色板精算出来的三条硬约束(写进 CSS 注释,防止后来者踩): 1. 苏维埃红 on 纯黑 = 2.96:1 → 禁止在黑底上用红字 2. 金星 on 纸 = 1.82:1 → 金星只能做图形或黑底文字 3. 棕 on 纯黑 = 2.45:1 → 禁止
已知未采用的规则:StyleKit 可导出 Figma tokens / Tailwind preset / SKILL.md;本项目是手写 CSS(无 Tailwind),未使用其导出产物。另有一个「动力学构成主义」变体,本页未使用。
9. 数据来源与验证状态
| 数据 | 来源 | 验证方式 |
|---|---|---|
| 字体西里尔覆盖 | Google Fonts 官方元数据 https://fonts.google.com/metadata/fonts(1950 个字族) |
程序化查询 subsets 字段,逐字族判定 |
| 字体字重轴 | 同上 | 程序化读取 fonts 对象的字重键 |
| 色值对比度 | WCAG 2.x 相对亮度公式 | PowerShell 脚本精算(脚本见 04-技术实现手册.md 附录),非目测 |
| 中文/开源字体许可证 | GitHub REST API api.github.com/repos/{owner}/{repo} |
读取 license.spdx_id 与 stargazers_count 实际返回 |
| 构成主义史料 | Tate、TheArtStory、MoMA、V&A | 直接抓取页面原文 |
⚠️ 未验证项:本环境
web_fetch无法访问 Wikimedia Commons / MoMA / V&A 的图片下载页(403 或不可达),因此公有领域图像素材的具体下载链接未经我直接验证,见03-资源清单.md中的明确标注。