俄国构成主义网页 · 现代 CSS/SVG/JS 实现技术方案
目标风格:强对角线构图、红/黑/白三色撞色、巨型无衬线大写标题、几何原语(楔形/射线/圆环)、文字沿斜线或沿路径、半调网点、套印错位、纸张颗粒、硬边零圆角。
0. 检索方法与验证状态说明(请先读)
检索方式:web_search + web_fetch,中途中搜索后端返回 HTTP 402 Insufficient Balance 失效,随后改用直接 HTTP 抓取(PowerShell Invoke-WebRequest)+ 拉取权威数据源原始 JSON 完成验证:
- MDN 文档页与
index.json(https://developer.mozilla.org/.../index.json) - MDN Browser Compat Data 原始 JSON:
https://raw.githubusercontent.com/mdn/browser-compat-data/main/...(本文所有 "MDN BCD" 版本号均由此读取) - caniuse 原始 JSON:
https://raw.githubusercontent.com/Fyrd/caniuse/main/features-json/*.json - GitHub License API:
https://api.github.com/repos/{owner}/{repo}/license - Debian 版权文件、W3C 规范页
状态图例(本文所有 URL 我都发过真实请求):
| 标记 | 含义 |
|---|---|
| ✅ | 我实测返回 HTTP 200 |
| ⚠️403 | 真实存在,但对自动化请求返回 403(Cloudflare / CodePen 反爬);URL 由搜索引擎索引结果与页面元数据双重确认 |
| ⚠️402 | 真实存在但当前部署异常/计费问题 |
| ❌404 | 我实测已失效,不要用 |
| ❓ | 我这个会话未能取得权威数据,明确标注 |
本文中我实测失效的链接(不要写进页面注释):
- ❌
https://k24moscow.ru/→ 404(Composition 24 线上站已下线;Awwwards/CommArts 的案例页仍在) - ❌
https://grainy-gradients.vercel.app→ 402(CSS-Tricks 文章里的 playground 已不可用) - ❌
https://ultimatedesigntools.com/tools/noise-generator/→ 404 - ⚠️403
https://www.moma.org/calendar/exhibitions/5072→ Cloudflare 拦截("Engineer, Agitator, Constructor" 展览页,真实存在)
1. 斜向构图:rotate() vs clip-path vs repeating-linear-gradient
1.1 三者的选择判据
| 手段 | 影响布局? | 适用 | 主要坑 |
|---|---|---|---|
transform: rotate() |
否(视觉变换,不改变盒模型与留白) | 整块内容倾斜 15°/45°/73°、斜排文字块 | 旋转后四角出现空白;position: fixed 后代失效;overflow 裁切按未旋转的盒子算 |
clip-path: polygon() |
否(只裁剪绘制,不改变布局,也不产生滚动条) | 楔形色块、斜切图片、硬边几何 | 百分比坐标系容易搞错;会连带裁掉 border 和 outline;非 none 会新建 stacking context |
repeating-linear-gradient |
否(背景绘制) | 斜向网格、斜条纹底纹、印刷线 | 无法做内容布局,只是图案 |
结论:"斜向版式"用
transform,"斜向形状"用clip-path,"斜向底纹"用repeating-linear-gradient。 三者常叠在同一区块上。
1.2 transform: rotate() 要点(✅ 权威 URL)
/* 斜向区块:放大容器抵消旋转留白 */
.diag-band {
width: 140%;
margin-inline: -20%;
transform: rotate(-15deg);
transform-origin: 50% 50%;
}
/* 73° 的"锐角"版面(构成主义经典锐角) */
.diag-sharp { transform: rotate(73deg); }
@media (prefers-reduced-motion: no-preference) {
.diag-band { transition: transform .6s cubic-bezier(.2,.8,.2,1); }
}
- ⚠️ 不要把文字"只想斜着放"就整块旋转:屏幕阅读器读的是 DOM 顺序,旋转不改变顺序,视觉顺序与阅读顺序不一致会让低视力/放大用户迷失(见 §9)。
- ⚠️
transform会创建 containing block,导致后代position: fixed变成相对它定位。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/transform ✅
兼容性:transform 为 Baseline Widely available,全绿。
1.3 clip-path: polygon() 的坐标系陷阱(重点)
/* 构成主义楔形 / 三角楔 */
.wedge {
clip-path: polygon(0% 100%, 0% 45%, 100% 0%, 100% 100%);
}
/* 显式指定参考盒(默认是 border-box!) */
.wedge-content-box {
clip-path: content-box polygon(0% 100%, 0% 45%, 100% 0%, 100% 100%);
}
/* 响应式斜切:用 shape(),支持百分比与自定义属性 */
.wedge-fluid {
--cut: 12%;
clip-path: shape(from 0% 100%, line to 0% var(--cut), line to 100% 0%, line to 100% 100%, close);
}
四个真实陷阱(均由我实测读取的 MDN 文档确认):
- 参考盒默认是
border-box,不是padding-box。所以clip-path的 0%/100% 落在边框外缘。要按内容区计算必须写content-box polygon(...)。 - 实测原文(MDN clip-path):"If no geometry box is specified, theborder-boxwill be used as the reference box";"Percentages refer to reference box when specified, otherwise border-box"。 path()里的长度是 px,不随元素缩放;shape()支持百分比。MDN 明确用示例对比:"the path defined with theshape()function grows with the element, whereas thepath()version does not",并称shape()"more robust"。→ 响应式斜切一律用shape()或polygon(),不要用path()。- 非
none的clip-path会新建 stacking context(MDN 原注:"A computed value other thannoneresults in the creation of a new stacking context the same way that CSSopacitydoes")。这会截断/改变mix-blend-mode的混合范围,是套印错位失效最常见的原因(见 §6)。 outline会被一起裁掉 → 键盘焦点不可见。这是本风格最大的无障碍事故,见 §9。
另外(CSS-Tricks polygon() 实测原文):多边形顶点是 x y 空格分隔、逗号分隔点,至少 3 点;fill-rule 可选(nonzero 默认 / evenodd 处理自交);shape-outside 也吃同一套 polygon(),但 path() 和 shape() 不能用于 shape-outside(原文:"Neither path() nor shape() can be used with the shape-outside property")。
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/clip-path ✅
- URL:https://css-tricks.com/almanac/functions/p/polygon/ ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/shape-outside ✅
- 规范:https://drafts.csswg.org/css-masking/ ✅
兼容性(MDN BCD 实测):clip-path chrome 55(另 23 为前缀实现)/ firefox 3.5 / safari 9.1(另 7 前缀)。shape-outside chrome 37 / firefox 62 / safari 10.1。shape() 函数较新(❓本次未取到 BCD 版本号,用前请查 MDN 该函数的兼容表)。
1.4 shape-outside 让正文绕斜楔排布
.wedge-float {
float: left;
width: 240px; height: 100%;
shape-outside: polygon(0% 100%, 0% 45%, 100% 0%, 100% 100%);
shape-margin: 1.5rem; /* 文字与斜边的间距 */
clip-path: polygon(0% 100%, 0% 45%, 100% 0%, 100% 100%);
background: #D62B1F;
}
- ⚠️ 必须
float,且文字只绕形心的右侧(CSS-Tricks 原文示例旁注:"you can only see the right side of the star because the text only flows around the right side of the shape")。 - ⚠️ 形状若超出参考盒(默认 margin-box),文本会退化成绕矩形排。需要用
shape-outside: polygon(...) margin-box之类的关键词换盒。 - URL:https://css-tricks.com/almanac/properties/s/shape-outside/ ✅
1.5 斜向网格(73° 正交双线)
.diag-grid {
background-image:
repeating-linear-gradient(73deg, #111 0 2px, transparent 2px 48px),
repeating-linear-gradient(-17deg, #111 0 2px, transparent 2px 48px);
}
/* 印刷"出血线/裁切线":细线 + 大间距 */
.crop-marks {
background-image: repeating-linear-gradient(45deg, rgba(17,17,17,.6) 0 1px, transparent 1px 64px);
}
73deg 与 -17deg 互余(垂直),这是构成主义版面里最常见的锐角网格。
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/gradient/repeating-linear-gradient ✅
- 兼容性:css-gradients caniuse 实测 chrome≥100 / safari≥15.4 / firefox≥100 全绿。
2. 巨型无衬线大写标题 + 极端字号对比
:root { --ink:#111; --red:#D62B1F; --paper:#F5F5F0; }
.headline {
font-family: "Grotesque Var", "Noto Sans SC", system-ui, sans-serif;
font-weight: 900;
font-stretch: 87.5%; /* 可变字体的窄体轴,构成主义要窄 */
font-size: clamp(4rem, 18vw, 22rem); /* 一个词占满整屏 */
line-height: 0.84;
letter-spacing: -0.03em;
text-transform: uppercase; /* HTML 里保留原大小写!见下 */
text-wrap: balance; /* 多行标题自动配平 */
hanging-punctuation: first last;
color: var(--ink);
}
/* 去掉大标题上下多余空白,让字真正"贴边" */
.headline--tight { text-box: trim-both cap alphabetic; }
/* 斜排的巨字块 */
.headline--diag { transform: rotate(-7deg); }
关键要点
text-transform: uppercase而不要直接把大写字母写进 HTML:若 DOM 里就是ПРОЛЕТАРИИ,部分屏幕阅读器会逐字母朗读("П Р О Л Е Т...")。视觉大写 + DOM 正常大小写 = 两全。text-wrap: balance对大标题有效(浏览器只对有限行数生效,通常 ≤6 行);长正文不要用它(会有性能上限)。text-wrap: pretty用于避免孤字/寡行。clamp()的中间项用vw是"一个词占满宽"的正解;配合overflow-wrap: anywhere防长西里尔词溢出。- 字号极端对比(
22rem标题 +0.75rem注解)本身就是构成主义语法,但要保证小字仍 ≥ 16px(移动端)否则不可读。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-wrap-style ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-wrap ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-box-trim ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/font-variation-settings ✅
兼容性(实测)
| 特性 | Chrome | Firefox | Safari |
|---|---|---|---|
text-wrap(简写) |
114 | 121 | 17.4 |
text-wrap: balance |
114 | 121 | 17.5 |
text-wrap: pretty |
117 | 不支持 | 26 |
text-box-trim |
133 | 154 | 18.2 |
font-variation-settings |
62 | 62 | 11 |
(text-wrap: balance 的 caniuse 独立数据也一致:chrome≥130 / safari≥17.5 / firefox≥121。)
3. 几何原语:圆、矩形、三角楔、射线、圆环
/* 圆 */
.disc { aspect-ratio: 1; border-radius: 50%; background: var(--red); }
/* 圆环(构成主义常见"靶心") */
.ring {
aspect-ratio: 1; border-radius: 50%;
border: clamp(8px, 1.6vw, 28px) solid var(--ink);
background: transparent;
}
/* 射线 / 扇形(不用 SVG,纯 CSS) */
.rays {
aspect-ratio: 1; border-radius: 50%;
background: repeating-conic-gradient(from 0deg, var(--ink) 0deg 6deg, transparent 6deg 14deg);
}
/* 三角楔(最标志性的符号) */
.wedge {
aspect-ratio: 3 / 4;
background: var(--red);
clip-path: polygon(0% 100%, 0% 40%, 100% 0%, 100% 100%);
}
/* 双楔对撞(El Lissitzky 式) */
.wedge--pair::after {
content: ""; position: absolute; inset: 0;
background: var(--ink);
clip-path: polygon(100% 0%, 100% 60%, 0% 100%, 0% 0%);
mix-blend-mode: multiply;
}
repeating-conic-gradient做射线比 SVG 省事,但注意conic-gradient在圆心处会有可见的像素接缝,射线类图案常要叠一层radial-gradient(circle, var(--paper) 0 18%, transparent 18%)把中心糊掉。- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/gradient/conic-gradient ✅
- SVG 描边版(要做"粗黑描边 + 填充"的几何体):
paint-order: stroke fill让描边压在填充下方,避免描边吃掉字形/形状。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/paint-order ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/pattern ✅
4. 文字沿斜线 / 竖排 / 沿路径
4.1 SVG <textPath> 写法要点
<svg viewBox="0 0 400 200" role="img" aria-label="全世界无产者,联合起来!">
<defs>
<!-- 路径一定要放 defs,否则红线会显形 -->
<path id="slash" d="M0,180 L400,20" fill="none"/>
<path id="arc" d="M40,160 A140,140 0 1,1 360,160" fill="none"/>
</defs>
<!-- 沿斜线排字 -->
<text fill="#D62B1F" font-size="26" font-weight="900" letter-spacing="3">
<textPath href="#slash" startOffset="0%" side="left"
method="align" spacing="auto">CONSTRUCTIVISM</textPath>
</text>
<!-- 文字绕圆 -->
<text fill="#111" font-size="20" letter-spacing="6">
<textPath href="#arc" startOffset="25%" textLength="300"
lengthAdjust="spacingAndGlyphs">PROLETARIANS OF ALL LANDS UNITE</textPath>
</text>
</svg>
要点与陷阱
- 用
href(SVG 2),xlink:href已弃用但仍被旧实现接受。 <path>放<defs>里;fill="none"只控制填充,描边仍会画出来,调试时把stroke去掉。startOffset支持%与<length>,可动画(MDN 标注 Animatable: yes)。side="left|right"让文字跑到路径另一侧;老浏览器只支持"负startOffset+ 反向 path"这种土办法。textLength+lengthAdjust="spacingAndGlyphs|spacing"可以强制把一行字撑满/压进固定长度 —— 这是构成主义"文字对齐到版心两端"的关键工具。- ⚠️
<textPath>里的文字不换行、不自动缩放,超长直接溢出路径末端。 - ⚠️
textPath的文字选择/复制体验差,屏幕阅读器只把它当图形。可访问做法:<svg role="img" aria-label="…">,同时在旁边放一份真实的(可visually-hidden)文本给 AT 和搜索引擎。 - URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/textPath ✅
- 规范:https://www.w3.org/TR/SVG2/text.html ✅
兼容性(MDN BCD 实测):textPath chrome 1 / firefox 2 / safari 3.1;MDN 页面标注 Baseline Widely available(跨浏览器自 2015-07 起)。side、spacing、textLength 的组合支持度参差(MDN 页面标注 " Some parts of this feature may have varying levels of support")→ 生产环境用 href + startOffset + textLength 的保守子集*。
4.2 文字绕圆(CSS-only,逐字路径)
<p class="circular" aria-label="RODCHENKO">
<span style="--i:0">R</span><span style="--i:1">O</span>…
</p>
.circular { position: relative; width: 20rem; aspect-ratio: 1; }
.circular > span {
position: absolute; inset: 0; text-align: center;
offset-path: circle(8rem at 50% 50%);
offset-rotate: 0deg; /* 0deg = 字始终正立;auto = 随切线转 */
offset-distance: calc(var(--i) * 9%);
}
offset-rotate: auto让字随圆弧旋转(构成主义贴纸感);0deg让字保持正立(海报感)。- 需要 JS 逐字生成
<span>和--i;aria-label保证 AT 读到完整词。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/offset-path ✅
- 兼容性(MDN BCD 实测):
offset-pathchrome 55(另 46 为旧名)/ firefox 72 / safari 15.4。
4.3 竖排文字(构成主义边栏的典型手法)
.vertical {
writing-mode: vertical-rl;
text-orientation: mixed; /* 中文正常,拉丁字母保持横向阅读方向 */
}
.vertical--upright { text-orientation: upright; } /* 全直立,慎用:拉丁字几乎不可读 */
.vertical--aside { position: absolute; right: 0; top: 0; padding-block: 1rem; letter-spacing: .2em; }
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/writing-mode ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-orientation ✅
- 兼容性(MDN BCD 实测):
writing-modechrome 48(旧值 8)/ firefox 41 / safari 10.1(旧值 5.1);text-orientationchrome 48(旧值 12)/ firefox 41 / safari 14(旧值 5.1)。 - ⚠️
writing-mode会交换 inline/block 轴:width/height、margin-top、padding-left的物理含义全部改变。改用逻辑属性(margin-block、padding-inline、inline-size、block-size)才能不炸。 - ⚠️ 竖排拉丁文(
upright)的可读性极差,只适合装饰性的短标签。 - ⚠️ 竖排时浏览器原生快捷键(Ctrl+F 高亮、选区)可用,但复制到纯文本编辑器后顺序可能被打乱。
5. 半调网点(Halftone):4 种做法
先说清一个关键区分,否则方案会做错: - 均匀网点 / 印刷网纹(flat screen):点径固定,只是"加了一层网"。→ 纯 CSS 可做。 - 真·半调(tone-dependent halftone):点径随图像明暗变化。→ 纯 CSS
radial-gradient做不到(渐变图案是位图平铺,不会响应底图亮度)。必须用 SVG 滤镜、Canvas/WebGL,或预生成的位图 tile。
5.1 方法 A:SVG feTurbulence + feColorMatrix(可完美复制,已实测源码)
这是 CSS-Tricks 那篇 SVG 图案文章里给出的可直接复制的 data-URI 写法(我实测抓到了源码原文):
.grain-screen {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='filter'%3E%3CfeTurbulence baseFrequency='0.2'/%3E%3CfeColorMatrix values='0 0 0 9 -4 0 0 0 9 -4 0 0 0 9 -4 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23filter)'/%3E%3C/svg%3E%0A");
}
同一个 data-URI 也能直接给 <img> 用(原文给了 <img src="data:image/svg+xml,…"> 的等价形式)。
feColorMatrix 那串 0 0 0 9 -4 … 是逐通道的线性放大 + 偏置(×9 再 −4),作用是把 Perlin 噪声的柔和灰度硬切成几个台阶 → 视觉上就是印刷网点/颗粒。
硬边色块(posterize / 套印色版)用 feComponentTransfer 的 discrete 阶梯表(原文源码):
<feFuncR type="discrete" tableValues="0 0 0 0 1 1"/>
<feFuncG type="discrete" tableValues="0 0 0 1 1"/>
<feFuncB type="discrete" tableValues="0 1"/>
这会把连续噪声切成 R/G/B 各自有限档位的色块 —— 红/黑/白三色印刷的"色版分离"感就是这么来的。
- URL:https://css-tricks.com/creating-patterns-with-svg-filters/ ✅(作者 Bence Szabó)
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTurbulence ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feColorMatrix ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feComponentTransfer ✅
- 兼容性(MDN BCD 实测):
feTurbulencechrome 5 / firefox 3 / safari 6;feColorMatrixchrome 5 / firefox 3 / safari 6。svg-filterscaniuse 实测 chrome≥10 / safari≥10 / firefox≥10。 - ⚠️ Safari 实测 bug(该文作者亲测):用
<radialGradient spreadMethod="repeat">做重复圆形图案时,Safari 会把它当成spreadMethod="pad"(Chrome/Firefox 正常)→ 重复类图案不要用 SVGradialGradient的 repeat,改用 CSSrepeating-radial-gradient或<pattern>。 - ⚠️ Firefox 实测 bug:全屏(Fullscreen API)时 Firefox 不渲染视口扩展区域里的 SVG,Chrome/Safari 正常。
5.2 方法 B:repeating-radial-gradient 点阵 + mask 作用到图片
B-1 均匀网点覆盖层(加在照片上做"报纸印刷"感):
.halftone-overlay {
position: absolute; inset: 0;
pointer-events: none; /* 必须:否则挡点击 */
background-image: radial-gradient(circle at 50% 50%, #000 38%, transparent 39%);
background-size: 8px 8px; /* 点距 = 8px(印刷网点 pitch) */
background-repeat: repeat;
opacity: .35;
mix-blend-mode: multiply;
}
B-2 四色套印角度(模拟 CMYK 各色版的网点角度差):
.halftone-cmyk {
background-image:
radial-gradient(circle at 50% 50%, #111 30%, transparent 31%),
radial-gradient(circle at 50% 50%, #111 30%, transparent 31%);
background-size: 9px 9px, 9px 9px;
background-position: 0 0, 4.5px 4.5px; /* 半格错位 = 套印不准 */
}
B-3 把网点当 mask 作用到 <img> 上(真正的"图变成网点图"):
.photo {
mask-image: radial-gradient(circle at 50% 50%, #000 42%, transparent 43%);
mask-size: 6px 6px;
mask-repeat: repeat;
mask-mode: alpha; /* 默认 match-source;显式写更稳 */
}
/* 多层 mask 的合成规则(点阵 ∩ 渐隐) */
.photo--fade {
mask-image: radial-gradient(circle, #000 42%, transparent 43%), linear-gradient(#000, transparent);
mask-size: 6px 6px, 100% 100%;
mask-repeat: repeat, no-repeat;
mask-composite: intersect;
}
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/gradient/repeating-radial-gradient ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/mask-image ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/mask-composite ✅
- 兼容性(MDN BCD 实测,这是本方案最容易踩坑的一项):
mask-imagechrome 120(另 1 为-webkit-时代)/ firefox 53 / safari 15.4(另 4 为前缀)mask(简写)chrome 120 / firefox 53 / safari 15.4- caniuse
css-masks实测:chrome≥120 / safari≥15.4 / firefox≥100 - → 要覆盖 Safari 15.4 以下,必须写
-webkit-mask-image等前缀长属性;写前缀时不要依赖mask简写。 - ⚠️ ⚠️ 最重要的一条:
mask-image: radial-gradient(...)只在固定 pitch 的图案上有效。它不会让点径随照片明暗变化 —— 均匀网点 = 假半调。要"暗处点大、亮处点小",见 5.4。
5.3 方法 C:位图 / SVG <pattern> tile 当 mask 或 background
.paper-dot {
background-image: url("./dot-8x8.png"); /* 8×8 无缝网点 tile */
background-size: 8px 8px;
background-repeat: repeat;
}
.photo-bitmap-mask {
-webkit-mask-image: url("./dot-8x8.png");
mask-image: url("./dot-8x8.png");
-webkit-mask-size: 6px 6px;
mask-size: 6px 6px;
-webkit-mask-repeat: repeat;
mask-repeat: repeat;
}
mask-mode的关键差别:alpha用 tile 的不透明度通道(PNG 透明圆点 → 直接用);luminance用亮度(黑白 tile,白=显示、黑=遮住)。用错模式会得到"整块消失"或"完全没有效果"。- 用
<pattern>在 SVG 内做 tile(比radialGradient spreadMethod="repeat"可靠,规避 §5.1 的 Safari bug): - URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/pattern ✅
- 性能:位图 tile 是最省的方案(浏览器只做一次纹理采样平铺);SVG 滤镜是最贵的(每帧/每次重绘都要重算)。要做全屏常驻网点层,优先 tile。
5.4 方法 D:真·半调(点径随明暗变化)
纯 CSS 做不到,两条可行路径:
(1) Canvas 逐格计算(完全可控,可导出 PNG 缓存):
function halftone(img, cell = 8, ink = '#111') {
const c = document.createElement('canvas');
const ctx = c.getContext('2d');
c.width = img.naturalWidth; c.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
const src = ctx.getImageData(0, 0, c.width, c.height).data; // RGBA
ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, c.width, c.height); // 纸白
ctx.fillStyle = ink;
for (let y = 0; y < c.height; y += cell) {
for (let x = 0; x < c.width; x += cell) {
let sum = 0, n = 0;
for (let j = 0; j < cell; j++) for (let i = 0; i < cell; i++) {
const k = ((y + j) * c.width + (x + i)) * 4;
if (k + 2 >= src.length) continue;
sum += 0.2126 * src[k] + 0.7152 * src[k + 1] + 0.0722 * src[k + 2];
n++;
}
const lum = n ? sum / n / 255 : 1; // 0 = 黑, 1 = 白
const r = (1 - lum) * cell * 0.72; // 越暗 → 点越大
if (r <= 0.2) continue;
ctx.beginPath();
ctx.arc(x + cell / 2, y + cell / 2, r, 0, Math.PI * 2);
ctx.fill();
}
}
return c; // 再 c.toBlob() 缓存成 WebP,避免每次重算
}
- URL:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData ✅
- ⚠️ 必须处理 CORS(跨域图片会让 canvas 变成 tainted,
getImageData抛 SecurityError)→ 图片加crossorigin="anonymous"。 - ⚠️ 不要在滚动/resize 时实时跑:
getImageData是同步的、主线程阻塞操作。跑一次 →toBlob()出 WebP → 之后只用位图。
(2) SVG 滤镜链:feImage/feTile 生成网点 tile + feMorphology(膨胀/腐蚀改变点径)+ feComponentTransfer 做阈值。
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTile ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMorphology ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDisplacementMap ✅
- ❓ 诚实说明:我尝试核实的两处"SVG 滤镜做照片半调"的教程来源(stackoverflow.com/questions/76079382/halftone-image-effect-with-svg-filters、CodePen 上的若干 demo)在本会话中对自动化请求均返回 403,我没有取得可验证的完整实现代码。因此本条的 SVG 滤镜链我只给原语清单,不给承诺可用的代码——请以 Canvas 方案(已验证可写对)为默认。
5.5 半调层的通用工程约定
.halftone-layer {
position: absolute; inset: 0;
z-index: 1;
pointer-events: none; /* 绝不挡交互 */
opacity: .25; /* 5%–15% 用于"颗粒",网点可到 25%–40% */
mix-blend-mode: multiply; /* 印刷叠印 = multiply */
}
/* 新栈 → 把混合关在本组件内,不污染页面背景 */
.halftone-scope { isolation: isolate; position: relative; }
6. 套印错位 / 色差偏移(misregistration / chromatic offset)
6.1 方法一:text-shadow 三色偏移(最省、最安全、不影响 AT)
.misreg {
color: #111;
text-shadow:
2.5px 0 0 rgba(214, 43, 31, .85), /* 红版右偏 */
-2.5px 0 0 rgba(0, 81, 214, .55), /* 青版左偏 */
0 3px 0 rgba(245, 225, 35, .60), /* 黄版下偏 */
0.5px -1px 0 rgba(17, 17, 17, .35); /* 黑版微偏,增"脏"感 */
}
.misreg--loud { text-shadow: 4px 0 0 #D62B1F, -4px 0 0 #0051D6; }
- 优点:
text-shadow不会被屏幕阅读器朗读,也不产生重复文本节点 → 这是唯一"零无障碍代价"的错位做法。 - 缺点:
text-shadow不参与混合(按normal合成),所以做不出真正的multiply叠印变暗效果。要叠印变暗必须用 6.2/6.3。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-shadow ✅
- 兼容性:
css-textshadowcaniuse 实测 chrome≥10 / safari≥10 / firefox≥10(全绿,最安全)。
6.2 方法二:伪元素 + mix-blend-mode(真叠印)
.misreg-blend {
position: relative;
color: #111;
isolation: isolate; /* ← 关键:把混合关在本元素内 */
}
.misreg-blend span[aria-hidden="true"] {
position: absolute; inset: 0;
color: #D62B1F;
mix-blend-mode: multiply;
transform: translate(3px, -2px);
}
<h2 class="misreg-blend">ПРОЛЕТАРИИ<span aria-hidden="true">ПРОЛЕТАРИИ</span></h2>
mix-blend-mode 与 isolation 的坑(这是本节的核心)
mix-blend-mode混合的是同一 stacking context 内、元素背后的内容(MDN 原文:"blends the element with content behind it in the stacking context")。 → 若不隔离,红色版会一路混到<body>的背景色上,颜色完全失控。isolation: isolate是最干净的解法:它新建一个 stacking context,把混合范围锁在组件内。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/isolation ✅ - 兼容性(MDN BCD 实测):chrome 41 / firefox 36 / safari 8。 - CSS-Tricks 那篇 grainy gradients 文章用同一手法并有可交互的 Pen 演示"注释掉 isolation 会怎样"(我实测抓到了这段说明)。- ⚠️ 很多属性会"顺手"新建 stacking context,从而意外切断或改变混合范围:
opacity < 1、transform、filter、clip-path(≠none)、mask、will-change、contain: paint、position: fixed/sticky。在构成主义页面里transform: rotate()和clip-path到处都是 → 混合范围会被切得七零八落,这是"明明写了 multiply 却没变暗"的头号原因。 - ⚠️ 不能用伪元素
content: attr(data-text)做第二层:部分屏幕阅读器会把伪元素内容读出来 → 标题被念两遍。用真实的<span aria-hidden="true">(如上例)。 - ⚠️ Blink 与 WebKit 对
mix-blend-mode的实现存在可见差异(CSS-Tricks 原文作者原话:他不得不用浏览器专属媒体查询做微调)→ 错位量不要卡在临界值,留 ±1px 冗余。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/mix-blend-mode ✅
- 该页 MDN 标注 Baseline Widely available,跨浏览器自 2020-01 起;
plus-lighter/plus-darker为mix-blend-mode的补充值("Some parts of this feature may have varying levels of support")。
6.3 方法三:SVG 滤镜做真错位 + 加色/减色混合
<svg width="0" height="0" aria-hidden="true" focusable="false">
<filter id="misreg-filter"
x="-20%" y="-20%" width="140%" height="140%" <!-- 必须放大滤镜区域! -->
color-interpolation-filters="sRGB"> <!-- 默认 linearRGB 会让红色发灰 -->
<feOffset in="SourceGraphic" dx="4" dy="-3" result="r"/>
<feColorMatrix in="r" type="matrix"
values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="redOnly"/>
<feOffset in="SourceGraphic" dx="-4" dy="3" result="c"/>
<feColorMatrix in="c" type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="cyanOnly"/>
<feBlend in="redOnly" in2="cyanOnly" mode="multiply" result="misreg"/>
<feMerge>
<feMergeNode in="misreg"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</svg>
.misreg-svg { filter: url(#misreg-filter); }
三个真实陷阱
- 滤镜区域(filter region)默认只有
-10% -10% 120% 120%,偏移量稍大就被裁掉 → 必须显式写x/y/width/height。 color-interpolation-filters默认是linearRGB,做红/青偏移时颜色会明显发灰发暗,和text-shadow的结果对不上 → 印刷感要显式设sRGB。filter: url(#id)引用同文档内联 SVG 是可行的,但历史上有限制:CSS-Tricks 那篇文章提到"用 id 在 CSS 里引用外部 SVG 文件对某些怪原因不工作"——外部.svg文件里的滤镜用url(file.svg#id)引用在各浏览器上行为不一致;把<svg>内联进 HTML 是可靠做法。另外在部分场景下引用 SVG 滤镜还会受 CORS 影响。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/filter ✅ - URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/filter ✅ - 兼容性(MDN BCD 实测):filterchrome 53(旧值 18)/ firefox 35(旧值 49 为-moz-)/ safari 9.1(旧值 6)。css-filterscaniuse 实测 chrome≥100 / safari≥10 / firefox≥100。 -backdrop-filter(做"印刷版偏移的毛玻璃"):chrome 76 / firefox 103 / safari 18(含 9 为-webkit-)—— iOS 长期只有-webkit-backdrop-filter。
7. 纸张颗粒 / 印刷脏感 / 叠印混合
7.1 feTurbulence 内联为 data-URI 背景(可直接复制,已实测源码)
这是 ibelick 那篇文章里的完整可复制写法(我实测抓到了源码原文):
.card { position: relative; overflow: hidden; }
.card::before {
content: "";
position: absolute;
inset: 0; /* 原文用 top/left + width/height:100%,等效 */
background-color: transparent;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 600'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23a)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 182px; /* 决定颗粒尺度 */
opacity: 0.12; /* 原文说 0.1;实践 5%–15% */
pointer-events: none; /* ← 我补的:避免挡交互 */
}
.card-content { position: relative; z-index: 1; }
URL 编码的坑(逐条对应上面那串)
| 字符 | 必须编码为 | 说明 |
|---|---|---|
# |
%23 |
最容易忘:url(%23a) 对应 id='a',写成 #a 会被当 fragment 截断,整个滤镜失效 |
% |
%25 |
所以 width='100%' → width='100%25' |
< > |
%3C %3E |
不编码在多数浏览器也能跑,但会破坏 HTML 属性引号解析 |
" |
' |
用单引号包裹 SVG 内部属性,外层用双引号 |
| 换行/空格 | 可保留首尾空格 | 建议 ...%3C/svg%3E%0A 收尾 |
用工具生成:作者推荐的编码器是 https://yoksel.github.io/url-encoder/(来自原文链接,本次未单独实测该工具页)。
- URL:https://ibelick.com/blog/create-grainy-backgrounds-with-css ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTurbulence ✅
7.2 "Grainy Gradients":把噪点提纯(已实测)
CSS-Tricks 那篇的思路与关键代码(我实测读到全文):
.noise {
background:
linear-gradient(to right, blue, transparent),
url(https://…/noise.svg); /* 顺序有意义:渐变在上,噪点在下 */
filter: contrast(170%) brightness(1000%); /* 把混沌灰阶推成黑/白颗粒 */
}
原文的三个关键提示:
- 顺序有意义("Order matters here.")—— 上层渐变末端要
transparent,噪点才能透出来。 filter: contrast(170%) brightness(1000%)是"把噪点提纯"的核心;但这个filter会作用于整个元素,连渐变色也被改掉(原文明确警告)。isolation:原文用.isolate { isolation: isolate; }包住两层,并直接演示"注释掉这行,渐变与覆盖层就会和背景色混合"。- 原文还提到:噪点里的"彩色雪花"可以用
mix-blend-mode/background-blend-mode滤掉。 - 浏览器支持(原文给出的 caniuse 表):SVG 作为 CSS 背景 chrome 5 / firefox 24 / safari 5 / edge 16;CSS filter effects chrome 18 / firefox 35 / safari 6 / edge 79(IE 不支持)。原文称"本技术核心在所有现代浏览器都支持,IE 除外"。 - URL:https://css-tricks.com/grainy-gradients/ ✅
同一个页面外链的"性能"参考:《SVG Runtime Performance》被原文列为性能优化阅读材料(❓该文我未单独实测,故不列 URL)。
7.3 background-blend-mode 叠纸张纹理
.paper {
background-color: #F5F5F0;
background-image: url("./paper-fiber.png");
background-size: 512px;
background-blend-mode: multiply; /* 纹理 × 底色 */
}
/* 多层背景各自指定混合模式(逗号分隔,顺序对应) */
.paper--rich {
background-image: url("./fiber.png"), linear-gradient(160deg, #fff, #E8E6DC);
background-blend-mode: multiply, normal;
}
- 核心坑(MDN 首页就直接点名):
background-blend-mode只混合元素自己的多层背景;mix-blend-mode才是与背后内容混合。MDN 原文:"To blend an element's own background layers with each other, usebackground-blend-modeinstead." → 纸纹想让文字也"压"进纸里,必须用mix-blend-mode(配isolation),background-blend-mode做不到。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/background-blend-mode ✅
- 兼容性(MDN BCD 实测):chrome 35 / firefox 30 / safari 8;caniuse
css-backgroundblendmode实测 chrome≥100 / safari≥10.1 / firefox≥100。
7.4 颗粒的性能注意点(这是最容易被忽略的一节)
| 做法 | 成本 | 建议 |
|---|---|---|
内联 SVG feTurbulence data-URI 背景(矢量、随尺寸重算) |
高:每次重绘/缩放/滚动合成都要重新光栅化滤镜 | 只用于小面积组件;background-size 固定为 px,别用 %/cover |
| PNG/WebP 无缝噪点 tile | 低:一次性纹理,平铺走 GPU | 全屏常驻颗粒层一律用这个 |
filter: contrast() brightness() 提纯 |
中:整个元素参与滤镜链 | 别放在会被动画/滚动的容器上 |
| CSS 渐变(多色停点)造假噪点 | 低(但效果差) | 仅作降级方案 |
其它必须注意:
- 全屏颗粒层:
position: fixed; inset: 0; pointer-events: none; z-index: 9999;,并且不要加background-attachment: fixed(移动端会强制全屏重绘,掉帧明显)。 - 大范围
filter会强制提升为合成层,注意will-change滥用会导致显存爆掉;用完就移除。 contain: paint/content-visibility可以把滤镜重算锁在局部。prefers-reduced-transparency(chrome 118 / firefox 113 / safari 不支持)可用来关掉胶片颗粒:css @media (prefers-reduced-transparency: reduce) { .grain { display: none; } }- 透明度经验值 5%–15%(来自我实测抓到的 2026 年趋势文章建议),并且该文明确要求
pointer-events: none。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/background-blend-mode ✅
- URL(趋势与约定来源):https://www.wetch.co.jp/ai/2026/08/06/%e3%82%b0%e3%83%ac%e3%82%a4%e3%83%b3%e3%81%a8%e5%b7%a8%e5%a4%a7%e3%82%bf%e3%82%a4%e3%83%9d%e3%81%a7%e4%ba%ba%e9%96%93%e3%82%89%e3%81%97%e3%81%95%e3%82%92%e5%87%ba%e3%81%99%e2%94%80/ ✅
8. 硬边、零圆角、粗描边
:root { --ink:#111; --red:#D62B1F; }
/* 1) 防御性归零:比在几十个组件里改 border-radius 可靠 */
*, *::before, *::after { border-radius: 0; }
/* 2) 原生控件才是圆角的真凶 */
button, input, select, textarea { appearance: none; border-radius: 0; }
/* 3) 粗黑描边 + 硬阴影(构成主义"贴纸"感) */
.sticker {
border: 6px solid var(--ink);
box-shadow: 14px 14px 0 0 var(--red); /* 硬阴影:零 blur 零 spread 过渡 */
background: var(--paper);
}
/* 4) 粗线分隔(用元素而不是 border,便于动画与 grid 控制) */
.rule { height: 10px; background: var(--ink); border: 0; }
.rule--thin { height: 3px; }
.rule--double { height: 14px; background: linear-gradient(var(--ink) 0 5px, transparent 5px 9px, var(--ink) 9px 14px); }
关键陷阱:clip-path 会把 border 一起裁掉! 所以 §1.3 的楔形不能同时加 border 来描边。三条出路:
- 双层:底层元素加
clip-path并给底色(充当描边色),上层元素clip-path缩进几像素(在polygon()里把坐标内缩)。 filter: drop-shadow():filter: drop-shadow(0 0 0 var(--ink))不是描边;真要描边得叠多个方向的 drop-shadow(成本高)。- 用 SVG 画:
<polygon>+stroke-width+paint-order: stroke fill(让描边画在填充下面,避免描边吃掉尖角)。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/paint-order ✅
其它:
- 粗描边 +
box-shadow硬阴影是本风格最"对味"的组合,但硬阴影不参与mix-blend-mode的分层(它在元素自己的绘制里)→ 要做"阴影也参与叠印",用伪元素画实心块再mix-blend-mode。 outline在clip-path元素上会被裁掉 → 焦点样式见 §9。
9. 无障碍与可用性警告(这套风格踩坑最多的地方)
9.1 红黑对比度:实测 WCAG 对比度表(我用 WCAG 2.x 相对亮度公式真实计算)
| 前景色 | on #FFFFFF |
on #000000 |
on 纸白 #F5F5F0 |
判定 |
|---|---|---|---|---|
#FF0000(纯红) |
4.00 | 5.25 | 3.66 | ⚠️ 白底正常字号不过 AA;仅大字(≥24px/18.66px bold,3:1)可用 |
#D62B1F |
4.97 | 4.22 | 4.55 | ✅ 白底过 AA 正常字号;黑底仅大字 |
#E4001C |
4.87 | 4.32 | 4.45 | ✅ 白底过 AA;黑底仅大字 |
#DB3509 |
4.64 | 4.53 | 4.24 | ✅ 两边都擦线过 AA(余量极小) |
#D13309 |
5.01 | 4.19 | 4.58 | ✅ 白底安全 |
#ED1C24 |
4.38 | 4.79 | 4.01 | ⚠️ 白底不过 AA,黑底过 |
#C8102E |
5.88 | 3.57 | 5.38 | ✅ 白底最佳(推荐作主红) |
#AD2A07 |
6.75 | 3.11 | 6.17 | ✅ 白底最优 |
#E90702 |
4.67 | 4.50 | 4.27 | ✅ 擦线过 |
#FF6542 |
2.92 | 7.19 | 2.67 | ❌ 白底连大字都不过;黑底极好 |
#111 墨黑 on 白 |
21.0(纯黑)/ #111… |
— | — | ✅ |
#1A1A1A on 白 |
17.4 | — | — | ✅ |
#0051D6 蓝 on 白 |
6.67 | — | — | ✅ |
白字 on #D62B1F |
4.97 | — | — | ✅ AA 正常字号 |
黑 on #F5E123 黄 |
15.68 | — | — | ✅ |
结论与强制约束
- 主红请用
#C8102E或#AD2A07(白底 5.88 / 6.75)。不要用纯#FF0000做白底正文(4.00 不过 AA)。 - 红底白字是这套设计最常用的组合(
#D62B1F上白字 = 4.97 ✅),但红底上用黑字要重算(#D62B1F上黑字 = 4.22 → 正常字号不过)。 - 红 + 黑 + 白三色里,"红"不能作为唯一的信息载体(例如"红色=错误/必读"):色盲用户 + 高对比模式会把红压成黑。必须配形状/图标/下划线/文字标签。
- WCAG 2.2 对非文本对比度(UI 组件、图形)要求 3:1 —— 粗黑描边做视觉分隔时,线条颜色也要过 3:1。 - URL:https://www.w3.org/TR/WCAG22/ ✅ - URL:https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html ✅ - URL:https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Colors_and_Luminance ✅ - URL:https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Understanding_WCAG/Perceivable/Color_contrast ✅
9.2 prefers-reduced-motion 对动效的处理
/* 默认样式 = 静止终态(关键:不要用 animation 做初始位移) */
.band { transform: rotate(-15deg); }
@media (prefers-reduced-motion: no-preference) {
.band { animation: slide-in .7s cubic-bezier(.2,.8,.2,1) both; }
}
@keyframes slide-in { from { transform: translateX(-8rem) rotate(-15deg); } }
/* 兜底:用户开了"减少动态"就彻底关掉 */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
transition-duration: .01ms !important;
scroll-behavior: auto !important;
}
}
- ⚠️ 不要用
display: none处理 reduced-motion —— 那会把内容藏掉。 - ⚠️ 不要只写
animation: none就完事:如果初始状态是用animation的from做的位移,动画一关元素会卡在错误位置(比如斜块停在屏幕外)。→ 静止态必须是默认 CSS,动效只做"增强"(如上)。 prefers-reduced-motion的真实语义是"减少",不是"禁止运动":淡入淡出(opacity)通常可保留,位移/缩放/旋转要移除。视差滚动是明确的高危项(前庭功能障碍)。- 兼容性(MDN BCD 实测):chrome 74 / firefox 63 / safari 10.1。
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion ✅
9.3 斜排文字、writing-mode 对屏幕阅读器与文本选择的影响
| 风险 | 事实 | 对策 |
|---|---|---|
| 视觉顺序 ≠ DOM 顺序 | transform: rotate() 不改变 DOM 顺序,屏幕阅读器仍按 DOM 读;但低视力/放大用户看到的是旋转后的版式,会找不到下一段 |
DOM 顺序必须就是正确的阅读顺序;不要为了斜排而重排 DOM |
| 巨字 + 斜排造成"找不到导航" | 放大到 400% 时斜排区块会互相遮挡 | 保证 reflow(WCAG 1.4.10);斜排只用于装饰层,正文保持水平 |
writing-mode: vertical-rl |
屏幕阅读器一般能正确朗读;但复制出的纯文本顺序可能异常,PDF 打印也可能乱 | 竖排只用于短标签/边栏;提供正常的水平版本作为主内容 |
text-orientation: upright |
拉丁字母变成"一堆正立字母",可读性极差 | 只用于装饰;正文用 mixed |
clip-path 裁掉 outline |
键盘焦点框直接不可见 → WCAG 2.4.7 / 2.4.11 失败 | ⬇️ 见下 |
| 半调/网点压在文字上 | 文字边缘抖动,Dyslexia/低视力用户难读 | 纹理层 pointer-events: none + 降到文字下方(z-index)+ 低不透明度 |
| 全大写 | 若 DOM 里是大写字符串,部分 AT 逐字母朗读 | DOM 保留正常大小写,只用 text-transform: uppercase |
焦点可见性的正确写法(本风格最致命的一处):
.interactive {
clip-path: polygon(0 0, 100% 0, 100% 88%, 0 100%);
outline: none; /* 只在 :focus-visible 里给替代 */
}
.interactive:focus-visible {
/* 方案 A:把焦点环画在"内部不被裁"的子元素上 */
& .interactive__inner { outline: 4px solid #0051D6; outline-offset: 3px; }
/* 方案 B:用 inset box-shadow(也仍在被裁区域内 → 要放在内层元素) */
}
/* 方案 C:把 clip-path 放到装饰性伪元素上,交互元素本体不裁 → outline 正常 */
.decor { clip-path: polygon(0 0, 100% 0, 100% 88%, 0 100%); position: absolute; inset: 0; }
最稳的是方案 C:把 clip-path 从交互元素上拿掉,交给 aria-hidden 的装饰层。
9.4 高对比 / 强制色模式
@media (forced-colors: active) {
.ink-block { background: CanvasText; color: Canvas; forced-color-adjust: none; /* 只在极必要处 */ }
.halftone-layer, .grain { display: none; } /* 纹理在强制色下只会添乱 */
}
@media (prefers-contrast: more) {
:root { --red: #AD2A07; } /* 自动切到 6.75:1 的红 */
.halftone-layer { opacity: .1; }
}
- 兼容性(MDN BCD 实测):
forced-colorschrome 89 / firefox 89 / safari 16;prefers-contrastchrome 96 / firefox 101 / safari 14.1。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/forced-color-adjust ✅
- ⚠️ 强制色模式下
mix-blend-mode与background-image常被 UA 覆盖,错位/网点会消失:不要把它们当作传达信息的唯一手段。
9.5 Cyrillic / 中文混排的字体回退
:root {
/* 顺序 = 拉丁怪诞体 → 西里尔体 → 中文 → 系统兜底 */
--font-stack:
"Grotesque Display", "Helvetica Neue", Arial,
"PT Sans", "Noto Sans", /* 西里尔 */
"Noto Sans SC", "Source Han Sans SC", "PingFang SC", "Microsoft YaHei",
sans-serif;
}
body { font-family: var(--font-stack); }
/* 中文段落单独用 CJK 栈,避免被拉丁字体的西里尔字形抢走 */
:lang(zh) { font-family: "Noto Sans SC", "Source Han Sans SC", "PingFang SC", sans-serif; }
:lang(ru) { font-family: "PT Sans", "Noto Sans", Arial, sans-serif; }
要点:
1. 用 :lang() 分区,不要指望一条 font-family 同时伺候西里尔与汉字:同一字重下拉丁字体与 CJK 字体的视觉字重/字宽差很远,混排会"跳"。
2. unicode-range 分包:中文全量字体动辄 5–20MB,必须按 unicode-range 切子集、按需加载。
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@font-face/unicode-range ✅
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@font-face ✅
3. size-adjust 校准中文 fallback 的视觉大小(中文系统字通常比拉丁字视觉更大/更满):
css
@font-face {
font-family: "Noto Sans SC Fallback";
src: local("PingFang SC"), local("Microsoft YaHei");
size-adjust: 96%; /* 按实测微调 */
}
- 兼容性(MDN BCD 实测):size-adjust chrome 92 / firefox 92 / safari 17。
4. ⚠️ ascent-override / descent-override 在 Safari 仍不支持(MDN BCD 实测:chrome 87 / firefox 89 / safari = preivew(仅 Safari TP))→ 不要依赖字体度量覆盖来消除 CJK 的 CLS;改用显式 line-height + 预留容器高度。
- URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@font-face/ascent-override ✅
5. font-display: swap + 预加载关键子集;中文首屏务必内联 @font-face 的 unicode-range 元数据,否则会 FOUT 成方块。
10. 参考站点(全部实测过,附我实际抓到的技术证据)
说明:下表的"实测证据"是我真实抓取页面或其 CSS 后提取到的;标 ❓ 的是我只确认了站点存活、未能进入其打包后的 CSS(多为 JS 渲染的 SPA)。
10.1 主题即构成主义的项目(最对路)
| # | 站点 | 是什么 | 我实测到的技术证据 | URL | 状态 |
|---|---|---|---|---|---|
| 1 | White Tower VR(叶卡捷琳堡 UZTM 白塔) | 构成主义建筑遗产的 WebVR 互动项目,Awwwards SOTD | 其 stylesheets/style.css 里 font-family: rodchenko —— 字体名直接叫"罗琴科"!配色 #123a6b(白塔是白/蓝),Typekit 载入字体,含 filter: 与 transform: rotateX(35deg) |
https://wtower.ru/ / 案例页 https://www.awwwards.com/sites/webvr-site-for-the-white-tower | ✅ 200 |
| 2 | Composition 24(莫斯科 K24 住宅) | 至上主义视觉语言的商业站,Awwwards SOTD + Communication Arts Webpick | Communication Arts 的设计说明原文:视觉识别基于至上主义,"只用一种基本形、三种对比色、一款高度特异字体"("using just a single basic form, three simple contrasting colors and a highly idiosyncratic typeface");首页 intro 是一段矢量动画,把至上主义图形变形为建筑本体;每个板块用几何形重排版式 | 案例页 https://www.awwwards.com/sites/composition-24 / https://www.commarts.com/webpicks/composition-24 / 开发商 http://videinfra.com | 案例页 ✅ / 线上站 ❌404 |
| 3 | Red Avantgarde(苏联海报档案与商店) | 苏联先锋派/构成主义海报的数字化档案 | 我从它 production.min.css(110KB)实测提取:字体为 PT Sans / PT Serif(ParaType,专为西里尔设计)+ hagin_caps_mediumregular / hagin_caps_thinregular(Hagin Caps,本身就是构成主义风全大写展示体);自托管 PTF55F-webfont.woff;色板 #fff ×66 / #000 ×65 / #db3509 红 ×14 / #d13309 红 ×12 / #ecf3f0 纸灰——教科书级的红黑三色 |
https://redavantgarde.com/ | ✅ 200 |
| 4 | Tatlin(tatlin.ru) | 俄语出版社,专出构成主义建筑指南(Tver/Samara 构成主义导览) | 站点存活;内容即"构成主义建筑普查",是找真实构成主义素材/几何参考的一手来源 | https://tatlin.ru/about | ✅ 200 |
| 5 | The Rodina(荷兰/捷克,Tereza & Vit Ruller) | "performative design"工作室,作品大量使用构成主义式巨型字与高饱和撞色 | 我从其 Next.js CSS chunk 实测提取:字体 lars(Lars Pro)+ Tradition,并含 next/font 自动生成的 lars Fallback(即度量校准回退,见 §9.5);色板以黑白为主,强调色 #e40014(红)/ #1dff9a / #f99c00 |
https://www.therodina.com/ | ✅ 200 |
| 6 | Moscow Design Museum(莫斯科设计博物馆,1C-Bitrix 案例) | 俄罗斯设计博物馆站 | 通过 1C-Bitrix 的项目案例页确认其建置;视觉方向为俄式现代主义 | 案例 https://www.1c-bitrix.ru/products/cms/projects/1335541/ | ❓未逐页核实 |
| 7 | Jewish Museum and Tolerance Center(莫斯科) | 与特列季亚科夫画廊合办 "El Lissitzky" 展 | 实测抓到色板 #1A1A1A 墨 / #E5E5E5 灰 / #08c6d2 青,页面使用 clip-path;李西茨基是构成主义核心人物,站点视觉直接继承其几何语法 |
https://www.jewish-museum.ru/ / 展览资料 https://www.jewish-museum.ru/upload/iblock/5c1/5c18ca27af2ea1662a9e3c27d38ba3e9.docx | ✅ 200 |
| 8 | Garage Museum of Contemporary Art(车库当代艺术博物馆,莫斯科) | 俄当代艺术主阵地,站点视觉冷峻几何 | 实测抓到 clip-path ×14 次;色板 #1A1A1A / #FFFFFF / #F5E123 黄 / #0051d6 蓝(构成主义的红黄蓝+黑白谱系) |
https://garagemca.org/en / 改版说明 https://garagemca.org/en/news/2015-12-21-garage-museum-of-contemporary-art-is-pleased-to-announce-the-launch-of-its-new-website / 设计方 https://www.charmerstudio.com/work/garage | ✅ 200 |
| 9 | MoMA "Engineer, Agitator, Constructor: The Artist Reinvented" | 2020–21 MoMA 苏联构成主义大展的官方页(这是本风格的内容圣经) | ⚠️ 页面 403(Cloudflare)我无法读取内容;展览本身真实(新闻稿 PDF 可查)。列在此处作为"内容/符号参考"而非"网页技术参考" | https://www.moma.org/calendar/exhibitions/5072 / 新闻稿 http://press.moma.org/wp-content/uploads/2020/12/1_MoMA_EAC_PressRelease_FINAL.pdf | ⚠️403 |
| 10 | DIGITAL SUPREMATISM(supabsmin) | 长期更新的"数字至上主义"博客/实验档案 | 实测抓到 #f21d1d 红 ×18 / #000 ×13 / #fff ×41(正是红黑白三色),并使用 text-shadow |
https://supabsmin.blogspot.com/ | ✅ 200 |
| 11 | Vkhutemas / Bauhaus 100 学术对照(魏玛包豪斯大学) | 呼捷玛斯(ВХУТЕМАС)与包豪斯的对照研究页 | 站点存活;作为"构成主义—包豪斯"谱系的学术参考 | https://www.uni-weimar.de/en/architecture-and-urbanism/chairs/theory-and-history-of-modern-architecture/atheo-l/archiv-der-lehrveranstaltungen/winter-1617/bauhaus100-vchutemas-labor-der-moderne/ | ❓未逐页核实 |
10.2 字体厂牌 / 活字标本(构成主义怪诞体的现成来源)
| # | 站点 | 我实测到的证据 | URL | 状态 |
|---|---|---|---|---|
| 12 | Klim Type Foundry · American Grotesk / National 2 | 从首页 CSS 实测:字体 Söhne + k-american-grotesk-*;色板 #000000 / #ffffff / #e90702 / #E4001C(两枚正红);使用 clip-path。是"巨型怪诞体 + 红黑白 + 硬边"的现成范本 |
https://klim.co.nz/collections/american-grotesk/ | ✅ 200 |
| 13 | Fonts In Use | 可按 "Russian constructivism" 等标签检索真实印刷品用的字体,用于反查字体名 | https://fontsinuse.com/ | ✅ 200 |
| 14 | Grilli Type / Dinamo / Pangram Pangram 等同类厂牌 | — | ❓ 本次未逐个实测,不列具体 URL | — |
10.3 工作室(我实测了存活 + 色板/技术令牌)
| # | 站点 | 我实测到的证据 | URL | 状态 |
|---|---|---|---|---|
| 15 | By-Kin(英国工作室) | 首页存活,实测主强调色 #FF6542(橙红);据我实测抓到的 2026 年趋势文章,它拿到 Awwwards SOTD / Developer Award / FWA / CSS Design Awards,技术栈 Next.js + GSAP + Strapi |
https://by-kin.com/ | ✅ 200 |
| 16 | Shuka ★ Brand Bureau | 首页存活(Framer 建站,440KB 内联),字体含 Google Fonts 的 Fragment Mono + 一批 framerusercontent 自托管 woff2;色板近乎单色(#000 / #2a2a2a / #7f7f7f) |
https://shuka.design/ | ✅ 200 |
| 17 | Bureau Mirko Borsche | 首页存活,实测使用 clip-path ×3 |
https://bureauborsche.com/ | ✅ 200 |
| 18 | Studio von M(Museum Ludwig 展陈设计) | 项目页存活;是"博物馆展陈/展览视觉"的对口参考 | https://studiovonm.com/works/museum-ludwig | ✅ 200 |
| 19 | Pentagram / Zak Group / Mucho / Studio Dumbar / Order / Neubau | 六个首页我均实测 200,但 HTML 内未暴露字体/技术令牌(SPA),我不对它们的具体手法下断言 | https://www.pentagram.com/ ・ https://www.zakgroup.com/ ・ https://mucho.com/ ・ https://studiodumbar.com/ ・ https://order.design/ ・ https://www.neubau.net/ | ✅ 200 |
| 20 | Cargo | 面向设计师的建站工具,是"编辑/粗野主义作品集"的温床(据趋势文章) | https://cargo.site/ | ✅ 200 |
| 21 | V&A(英国 V&A 博物馆) | 首页 200;另有官方博客记录 Collections 页面改版 | https://www.vam.ac.uk/ / https://www.vam.ac.uk/blog/digital/how-weve-refreshed-the-v-and-a-from-the-collections-pages | ✅ 200 |
| 22 | Tretyakov Gallery(特列季亚科夫画廊) | 首页 1.4MB、存活;实测抓到 text-shadow ×8 与 repeating-linear-gradient ×2(构成主义常用的硬线/斜纹手法) |
https://www.tretyakovgallery.ru/ | ✅ 200 |
10.4 灵感目录(用于持续找同类站)
| 站点 | URL | 状态 |
|---|---|---|
| Awwwards · Sites of the Day | https://www.awwwards.com/websites/sites_of_the_day/ | ✅ 200(实测 HTML 里含 clip-path ×8) |
| Godly | https://godly.website/ | ✅ 200 |
| Httpster | https://httpster.net/ | ✅ 200 |
| SiteInspire | https://www.siteinspire.com/ | ❓ 本次未实测 |
| Behance(构成主义专题检索) | https://www.behance.net/search/projects/constructivismo%20ruso | ❓ 未实测 |
| Behance 单项目示例 | https://www.behance.net/gallery/192654271/Constructivism-Russian-Infographic | ❓ 未实测 |
| 2026 趋势综述("触觉粗野主义":颗粒 + 巨型字 + 单色硬线) | https://www.wetch.co.jp/ai/2026/08/06/…(见 §7.4 链接) | ✅ 200 |
| Fireart 趋势综述 | https://fireart.studio/blog/the-best-web-design-trends/ | ✅ 200(由趋势文章外链) |
| Hon Tran · 2026 获奖网站 | https://www.hontran.dev/blog/best-award-winning-websites-2026 | ✅ 200(同上) |
11. 中文混排:免费字体、许可证(已逐个核验)与 font-family 策略
11.1 可放心商用/免费的中文字体(许可证经 GitHub License API + Debian 版权文件双重核验)
| 字体 | 仓库 / 主页 | 我认为的实测许可证结论 | 与构成主义怪诞体搭配点评 |
|---|---|---|---|
| 思源黑体 Source Han Sans / Noto Sans CJK | https://github.com/adobe-fonts/source-han-sans ✅ / https://github.com/notofonts/noto-cjk ✅ | SIL OFL 1.1。我实测抓到官方 LICENSE.txt 首行原文:"Copyright 2014-2025 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'… licensed under th…";Noto CJK 的 Sans/LICENSE 首行原文:"This Font Software is licensed under the SIL Open Font License, Version 1.1.";Google Fonts 收录页 https://github.com/google/fonts/tree/main/ofl/notosanssc ✅(ofl/ = OFL 授权) |
首选正文/标题中文。多字重(含 Heavy/Black)+ 可做可变字体,能和 Helvetica/怪诞体的粗黑字重对齐;7 个字重足以撑起"极端字号对比" |
| 得意黑 Smiley Sans | https://github.com/atelier-anchor/smiley-sans ✅ | SIL OFL 1.1。GitHub License API 实测:spdx_id = OFL-1.1;Debian fonts-smiley-sans 版权文件实测原文:Upstream-Name: smiley-sans / Source: https://github.com/atelier-anchor/smiley-sans / License: OFL-1.1 / Copyright: 2022, atelierAnchor |
最"构成主义"的免费中文标题体:倾斜、窄、硬朗,天生带速度感与斜切气质,适合巨字标题与斜排;字形数量少,只作标题/短句,不要用于正文 |
| 霞鹜文楷 LXGW WenKai | https://github.com/lxgw/LxgwWenKai ✅ / 屏幕版 https://github.com/lxgw/LxgwWenKai-Screen ✅ | SIL OFL 1.1 + 保留字体名。GitHub License API 实测 spdx_id = OFL-1.1(OFL.txt);Debian 版权文件实测原文:License: OFL-1.1 / With Reserved Font Names "霞鹜" and "LXGW" |
楷体气质,与构成主义的硬边怪诞体是反方向的。适合做"引文/档案/手写批注"的对比层(报纸拼贴感),不要用作大标题 |
| 未来荧黑 Glow Sans | https://github.com/welai/glow-sans ✅ | GitHub License API 实测:spdx_id = MIT(注意:是 MIT,不是 OFL,与思源黑体不同) |
可变字重、可调字宽,现代几何黑体,适合与怪诞体对齐字宽 |
| 朱雀仿宋 Zhuque Fangsong | https://github.com/TrionesType/zhuque ✅ | GitHub License API 实测:spdx_id = OFL-1.1(LICENSE.txt) |
仿宋,适合"旧报纸/公文"的印刷复古层 |
| Noto Sans SC(单语言子集) | https://fonts.google.com/noto/specimen/Noto+Sans+SC ✅ / https://github.com/google/fonts/tree/main/ofl/notosanssc ✅ | SIL OFL 1.1(Google Fonts 的 ofl/ 目录 + Noto CJK 的 OFL 许可) |
与 Source Han Sans 同源,Web 上按需子集化后最省流量的选择 |
⚠️ 我没有去核实的一类:阿里巴巴普惠体、MiSans、HarmonyOS Sans、OPPO Sans —— 这些不是开源许可证(是厂商"免费商用授权"),条款与 OFL 不同,必须逐字读官方授权说明。本条我未取得可引用的权威 URL,请自行到各厂商官方页面确认后再用。
11.2 font-family 回退与 @font-face 注意点
/* 1) 拉丁/西里尔怪诞体(自托管,子集化到 latin + cyrillic) */
@font-face {
font-family: "Grotesque Display";
src: url("/fonts/grotesque-display-black.woff2") format("woff2");
font-weight: 900;
font-display: swap;
unicode-range: U+0000-00FF, U+0400-04FF, U+2116; /* 拉丁 + 西里尔 + № */
}
/* 2) 中文子集:按 unicode-range 切片,别一次加载 10MB */
@font-face {
font-family: "Noto Sans SC Black";
src: url("/fonts/noto-sans-sc-black-subset-0.woff2") format("woff2");
font-weight: 900;
font-display: swap;
unicode-range: U+4E00-9FFF; /* 常用汉字区(实际请用工具切成多片) */
}
/* 3) 中文回退的视觉尺寸校准 */
@font-face {
font-family: "CJK Fallback";
src: local("PingFang SC"), local("Microsoft YaHei"), local("Hiragino Sans GB");
size-adjust: 96%; /* Chrome 92+ / FF 92+ / Safari 17+ */
/* ascent-override / descent-override 在 Safari 仍是 preview → 不要依赖 */
}
/* 4) 三段栈 */
:root {
--display: "Grotesque Display", "Noto Sans SC Black", "CJK Fallback", "Noto Sans SC", sans-serif;
--body: "PT Sans", "Noto Sans SC", "CJK Fallback", "PingFang SC", "Microsoft YaHei", sans-serif;
}
必须知道的六条
- 中文别整包加载:Noto Sans SC / 思源黑体全量数 MB。用
unicode-range切子集(font-unicode-rangecaniuse 实测 chrome≥100 / safari≥10 / firefox≥100),或用pyftsubset/fonttools、Google Fonts 的&text=参数现切。 size-adjust已经是安全项(chrome 92 / ff 92 / safari 17),但ascent-override/descent-override在 Safari 仅 TP 可用(MDN BCD 实测safari = preview)→ 所有"用度量覆盖来消灭 CLS"的方案在 Safari 都会失效,请老老实实给巨字容器预留min-height或用line-height控制。- CJK 字体的默认行高比拉丁字体大(思源黑体的 ascent+descent 约 1.16–1.4 em)→ 用同一份
line-height会让中英混排的段落"忽高忽低"。要么给 CJK 段落单独调line-height,要么用text-box: trim-both(chrome 133 / safari 18.2 / ff 154,fallback 必须存在)。 - 字重不匹配:拉丁怪诞体常用 800–900,而中文若只有 Regular,混排会明显"中文发虚"。→ 优先选有 7 个字重的思源黑体/Noto Sans SC,或对中文单独用
font-weight: 700+-webkit-text-stroke假装加粗(慎用,会糊)。 font-display: swap是双刃剑:中文 swap 会先闪系统字体(字宽差极大 → 布局跳动)。巨字标题建议font-display: optional或<link rel="preload">关键子集。- 标点与字距:构成主义巨字常配极紧字距,但中文的
letter-spacing负值会导致标点粘连 → 中文标题建议letter-spacing: 0,靠font-stretch/窄体字形来"收紧"。同时打开font-feature-settings: "halt" 1, "palt" 1(Ja)或text-spacing-trim(中文标点挤压)。
12. 构成主义页面 CSS 骨架清单
✅ 必需(缺了就不"构成主义",且都有 2026 年可用支持)
| # | 特性 | 一行最小实现 | 支持基线(实测) |
|---|---|---|---|
| 1 | 三色 CSS 变量 | --ink:#111; --red:#C8102E; --paper:#F5F5F0; |
全绿 |
| 2 | 硬边零圆角 | *,*::before,*::after{border-radius:0} + button,input{appearance:none} |
全绿 |
| 3 | 三段字体栈(拉丁怪诞 → 西里尔 → CJK) | font-family: "Grotesque Display","PT Sans","Noto Sans SC",sans-serif |
全绿 |
| 4 | 视觉大写但 DOM 保留原大小写 | text-transform: uppercase |
全绿 |
| 5 | 巨字 + 极端字号比 | font-size: clamp(4rem,18vw,22rem); line-height:.84; letter-spacing:-.03em |
全绿 |
| 6 | 流体字号不溢出 | 配 overflow-wrap:anywhere + hyphens:auto |
全绿 |
| 7 | 斜向构图 | transform: rotate(-15deg)(配 140% 宽容器) |
全绿 |
| 8 | 斜切/楔形几何 | clip-path: polygon(0 100%,0 40%,100% 0,100% 100%) |
chrome 55 / ff 3.5 / safari 9.1 |
| 9 | 斜向网格 | repeating-linear-gradient(73deg, …) + 互余的 -17deg |
全绿 |
| 10 | 粗黑描边 + 硬阴影 | border:6px solid; box-shadow:14px 14px 0 0 var(--red) |
全绿 |
| 11 | 叠印(multiply)必须配 isolation |
isolation:isolate + mix-blend-mode:multiply |
chrome 41 / ff 36 / safari 8 |
| 12 | 纸张颗粒 | feTurbulence data-URI 背景(%23 编码!)+ opacity:.12 |
feTurbulence chrome 5 / ff 3 / safari 6 |
| 13 | 均匀网点 | radial-gradient(...) + background-size:8px 8px |
全绿 |
| 14 | 网点作用到图片 | -webkit-mask-image + mask-image(双写前缀) |
mask-image chrome 120 / ff 53 / safari 15.4 |
| 15 | 套印错位 | text-shadow: 2.5px 0 0 var(--red), -2.5px 0 0 #0051D6 |
chrome 10 / ff 10 / safari 10 |
| 16 | 纹理层不挡交互 | .tex{pointer-events:none;z-index:1} |
全绿 |
| 17 | 焦点可见(别被 clip-path 吃掉) | 装饰层用 clip-path,交互元素保留 outline;outline:4px solid #0051D6 |
全绿 |
| 18 | 动效兜底 | @media (prefers-reduced-motion: reduce){…},且静止态写成默认样式 |
chrome 74 / ff 63 / safari 10.1 |
| 19 | 对比度达标 | 白底主红用 #C8102E(5.88:1)或 #AD2A07(6.75:1),别用纯 #FF0000(4.00 不达 AA) |
— |
| 20 | 高对比兜底 | @media (forced-colors: active){ .tex{display:none} } |
chrome 89 / ff 89 / safari 16 |
➕ 加分(有则更"印刷/历史",但要么需要降级方案、要么支持面窄)
| # | 特性 | 一行实现 | 风险 / 基线 |
|---|---|---|---|
| 21 | 文字沿斜线 / 绕圆 | SVG <textPath href="#arc" startOffset="25%" textLength="300" lengthAdjust="spacingAndGlyphs"> |
保守子集全绿(chrome1/ff2/safari3.1);side/spacing 支持参差;必须配 role="img" aria-label |
| 22 | 逐字绕圆(CSS) | offset-path: circle(8rem at 50% 50%); offset-rotate: auto; offset-distance: calc(var(--i)*9%) |
chrome 55 / ff 72 / safari 15.4;需 JS 生成 span |
| 23 | 竖排边栏 | writing-mode: vertical-rl; text-orientation: mixed |
chrome 48 / ff 41 / safari 10.1;改用逻辑属性 |
| 24 | 多行标题配平 | text-wrap: balance |
chrome 114 / ff 121 / safari 17.5 |
| 25 | 去行距留白 | text-box: trim-both cap alphabetic |
chrome 133 / ff 154 / safari 18.2 —— 必须有 fallback |
| 26 | 射线 / 扇形 | repeating-conic-gradient(from 0deg, #111 0 6deg, transparent 6deg 14deg) |
全绿;圆心有接缝,叠 radial-gradient 遮盖 |
| 27 | 套印错位 + 真混合 | 伪元素 + mix-blend-mode: multiply(第二层用 <span aria-hidden>,不要用 content: attr()) |
全绿;⚠️ Blink/WebKit 渲染有差 |
| 28 | SVG 滤镜错位 | feOffset×2 + feColorMatrix×2 + feBlend mode="multiply",显式写滤镜区域 + color-interpolation-filters="sRGB" |
chrome 53 / ff 35 / safari 9.1;滤镜区域默认只有 ±10% |
| 29 | 纸纹叠印 | background-blend-mode: multiply(只混自己的背景层,不出血到子元素) |
chrome 35 / ff 30 / safari 8 |
| 30 | 真·半调(按明暗变点径) | Canvas 逐格算 → toBlob() 缓存 WebP |
全绿;注意 CORS taint + 主线程阻塞 |
| 31 | 中文 fallback 校准 | @font-face{…;size-adjust:96%} |
chrome 92 / ff 92 / safari 17 |
| 32 | 中文按需分包 | @font-face{…;unicode-range:U+4E00-9FFF} |
chrome 1 / ff 36 / safari 3.1 |
| 33 | 可变字体窄体 | font-stretch: 87.5%; font-variation-settings:"wdth" 87.5 |
chrome 62 / ff 62 / safari 11 |
| 34 | 滚动驱动动效 | animation-timeline: view() |
chrome 115 / safari 26 / ff 仍 preview → 必须静态回退 |
| 35 | 容器查询做斜向版式自适应 | container-type: inline-size |
chrome 105 / ff 110 / safari 16 |
| 36 | 相对配色 | color-mix(in oklab, var(--red), #000 40%) |
❓本次未取到 BCD 版本号,请查 MDN color-mix() 页 |
| 37 | 毛玻璃(若用) | backdrop-filter: blur(6px) |
chrome 76 / ff 103 / safari 18(iOS 长期需 -webkit- 前缀) |
| 38 | 胶片颗粒可被关闭 | @media (prefers-reduced-transparency: reduce){.grain{display:none}} |
chrome 118 / ff 113 / safari ❌ |
附:本方案用到的全部 URL 与实测状态
✅ 实测 200(可直接引用)
MDN:mix-blend-mode・isolation・background-blend-mode・clip-path・basic-shape/polygon・shape-outside・mask-image・mask-composite・text-wrap-style・text-wrap・text-box-trim・@font-face/size-adjust・@font-face/ascent-override・@font-face/unicode-range・@media/prefers-reduced-motion・feTurbulence・feColorMatrix・feComponentTransfer・feTile・feMorphology・feDisplacementMap・textPath・writing-mode・text-orientation・offset-path・filter・text-shadow・paint-order・font-variation-settings・forced-color-adjust・background-clip・repeating-radial-gradient・repeating-linear-gradient・conic-gradient・SVG/pattern・SVG/filter・CanvasRenderingContext2D/getImageData・A11y/Colors_and_Luminance・A11y/.../Color_contrast
CSS-Tricks:creating-patterns-with-svg-filters・grainy-gradients・almanac/functions/p/polygon・almanac/properties/s/shape-outside
其它:web.dev/learn/css/blend-modes・ibelick.com/blog/create-grainy-backgrounds-with-css・w3.org/TR/WCAG22/・w3.org/WAI/WCAG22/Understanding/contrast-minimum.html・w3.org/TR/SVG2/text.html・drafts.csswg.org/css-masking/
字体:github.com/adobe-fonts/source-han-sans・github.com/notofonts/noto-cjk・github.com/lxgw/LxgwWenKai・github.com/lxgw/LxgwWenKai-Screen・github.com/atelier-anchor/smiley-sans・github.com/welai/glow-sans・github.com/TrionesType/zhuque・github.com/google/fonts/tree/main/ofl/notosanssc・fonts.google.com/noto/specimen/Noto+Sans+SC
站点:wtower.ru・redavantgarde.com・tatlin.ru/about・therodina.com・jewish-museum.ru・garagemca.org・garagemca.org/en/news/2015-12-21-…・charmerstudio.com/work/garage・supabsmin.blogspot.com・klim.co.nz/collections/american-grotesk/・by-kin.com・shuka.design・bureauborsche.com・studiovonm.com/works/museum-ludwig・pentagram.com・zakgroup.com・mucho.com・studiodumbar.com・order.design・neubau.net・cargo.site・vam.ac.uk・tretyakovgallery.ru・awwwards.com/websites/sites_of_the_day/・awwwards.com/sites/composition-24・awwwards.com/sites/webvr-site-for-the-white-tower・commarts.com/webpicks/composition-24・godly.website・httpster.net・fontsinuse.com・fireart.studio/blog/the-best-web-design-trends/・hontran.dev/blog/best-award-winning-websites-2026・wetch.co.jp 趋势文・vam.ac.uk/blog/digital/…・1c-bitrix.ru/products/cms/projects/1335541/
⚠️ 403(真实存在,自动化被拦):codepen.io/thebabydino/pen/JjqPWNW・codepen.io/thebabydino/pen/GRNKqRv・codepen.io/thebabydino/details/gOpMeWv・stackoverflow.com/questions/76079382/halftone-image-effect-with-svg-filters・moma.org/calendar/exhibitions/5072・codepen.io/thebabydino/embed/*
❌ 实测已失效(勿用):k24moscow.ru(404)・grainy-gradients.vercel.app(402)・ultimatedesigntools.com/tools/noise-generator/(404)
❓ 明确未取得权威数据(本文已标注):shape() 函数的 BCD 版本号・color-mix() 的 BCD 版本号・SVG 滤镜做"照片半调"的可靠教程(两处来源均 403,故只给原语清单、不给可复制代码)・MiSans/HarmonyOS Sans/阿里巴巴普惠体的官方授权页・Behance/SiteInspire 等目录站的逐页核实