← 目录 05 / 11

俄国构成主义网页 · 现代 CSS/SVG/JS 实现技术方案

目标风格:强对角线构图、红/黑/白三色撞色、巨型无衬线大写标题、几何原语(楔形/射线/圆环)、文字沿斜线或沿路径、半调网点、套印错位、纸张颗粒、硬边零圆角。


0. 检索方法与验证状态说明(请先读)

检索方式:web_search + web_fetch,中途中搜索后端返回 HTTP 402 Insufficient Balance 失效,随后改用直接 HTTP 抓取(PowerShell Invoke-WebRequest)+ 拉取权威数据源原始 JSON 完成验证:

状态图例(本文所有 URL 我都发过真实请求):

标记 含义
✅ 我实测返回 HTTP 200
⚠️403 真实存在,但对自动化请求返回 403(Cloudflare / CodePen 反爬);URL 由搜索引擎索引结果与页面元数据双重确认
⚠️402 真实存在但当前部署异常/计费问题
❌404 我实测已失效,不要用
❓ 我这个会话未能取得权威数据,明确标注

本文中我实测失效的链接(不要写进页面注释):


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); }
}

兼容性: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 文档确认):

  1. 参考盒默认是 border-box,不是 padding-box。所以 clip-path 的 0%/100% 落在边框外缘。要按内容区计算必须写 content-box polygon(...)。 - 实测原文(MDN clip-path):"If no geometry box is specified, the border-box will be used as the reference box";"Percentages refer to reference box when specified, otherwise border-box"。
  2. path() 里的长度是 px,不随元素缩放;shape() 支持百分比。MDN 明确用示例对比:"the path defined with the shape() function grows with the element, whereas the path() version does not",并称 shape() "more robust"。→ 响应式斜切一律用 shape() 或 polygon(),不要用 path()。
  3. 非 none 的 clip-path 会新建 stacking context(MDN 原注:"A computed value other than none results in the creation of a new stacking context the same way that CSS opacity does")。这会截断/改变 mix-blend-mode 的混合范围,是套印错位失效最常见的原因(见 §6)。
  4. 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")。

兼容性(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;
}

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); }

关键要点

兼容性(实测)

特性 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;
}

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>

要点与陷阱

兼容性(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%);
}

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; }

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 各自有限档位的色块 —— 红/黑/白三色印刷的"色版分离"感就是这么来的。

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;
}

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;
}

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,避免每次重算
}

(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; }

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 的坑(这是本节的核心)

  1. mix-blend-mode 混合的是同一 stacking context 内、元素背后的内容(MDN 原文:"blends the element with content behind it in the stacking context")。 → 若不隔离,红色版会一路混到 <body> 的背景色上,颜色完全失控。
  2. 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 会怎样"(我实测抓到了这段说明)。
  3. ⚠️ 很多属性会"顺手"新建 stacking context,从而意外切断或改变混合范围:opacity < 1、transform、filter、clip-path(≠none)、mask、will-change、contain: paint、position: fixed/sticky。在构成主义页面里 transform: rotate() 和 clip-path 到处都是 → 混合范围会被切得七零八落,这是"明明写了 multiply 却没变暗"的头号原因。
  4. ⚠️ 不能用伪元素 content: attr(data-text) 做第二层:部分屏幕阅读器会把伪元素内容读出来 → 标题被念两遍。用真实的 <span aria-hidden="true">(如上例)。
  5. ⚠️ Blink 与 WebKit 对 mix-blend-mode 的实现存在可见差异(CSS-Tricks 原文作者原话:他不得不用浏览器专属媒体查询做微调)→ 错位量不要卡在临界值,留 ±1px 冗余。
  6. 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); }

三个真实陷阱

  1. 滤镜区域(filter region)默认只有 -10% -10% 120% 120%,偏移量稍大就被裁掉 → 必须显式写 x/y/width/height。
  2. color-interpolation-filters 默认是 linearRGB,做红/青偏移时颜色会明显发灰发暗,和 text-shadow 的结果对不上 → 印刷感要显式设 sRGB。
  3. 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 实测):filter chrome 53(旧值 18)/ firefox 35(旧值 49 为 -moz-)/ safari 9.1(旧值 6)。css-filters caniuse 实测 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/(来自原文链接,本次未单独实测该工具页)。

7.2 "Grainy Gradients":把噪点提纯(已实测)

CSS-Tricks 那篇的思路与关键代码(我实测读到全文):

.noise {
  background:
    linear-gradient(to right, blue, transparent),
    url(https://…/noise.svg);          /* 顺序有意义:渐变在上,噪点在下 */
  filter: contrast(170%) brightness(1000%);   /* 把混沌灰阶推成黑/白颗粒 */
}

原文的三个关键提示:

  1. 顺序有意义("Order matters here.")—— 上层渐变末端要 transparent,噪点才能透出来。
  2. filter: contrast(170%) brightness(1000%) 是"把噪点提纯"的核心;但这个 filter 会作用于整个元素,连渐变色也被改掉(原文明确警告)。
  3. isolation:原文用 .isolate { isolation: isolate; } 包住两层,并直接演示"注释掉这行,渐变与覆盖层就会和背景色混合"。
  4. 原文还提到:噪点里的"彩色雪花"可以用 mix-blend-mode / background-blend-mode 滤掉。
  5. 浏览器支持(原文给出的 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;
}

7.4 颗粒的性能注意点(这是最容易被忽略的一节)

做法 成本 建议
内联 SVG feTurbulence data-URI 背景(矢量、随尺寸重算) 高:每次重绘/缩放/滚动合成都要重新光栅化滤镜 只用于小面积组件;background-size 固定为 px,别用 %/cover
PNG/WebP 无缝噪点 tile 低:一次性纹理,平铺走 GPU 全屏常驻颗粒层一律用这个
filter: contrast() brightness() 提纯 中:整个元素参与滤镜链 别放在会被动画/滚动的容器上
CSS 渐变(多色停点)造假噪点 低(但效果差) 仅作降级方案

其它必须注意:


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 来描边。三条出路:

  1. 双层:底层元素加 clip-path 并给底色(充当描边色),上层元素 clip-path 缩进几像素(在 polygon() 里把坐标内缩)。
  2. filter: drop-shadow():filter: drop-shadow(0 0 0 var(--ink)) 不是描边;真要描边得叠多个方向的 drop-shadow(成本高)。
  3. 用 SVG 画:<polygon> + stroke-width + paint-order: stroke fill(让描边画在填充下面,避免描边吃掉尖角)。 - URL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/paint-order ✅

其它:


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 — — ✅

结论与强制约束

  1. 主红请用 #C8102E 或 #AD2A07(白底 5.88 / 6.75)。不要用纯 #FF0000 做白底正文(4.00 不过 AA)。
  2. 红底白字是这套设计最常用的组合(#D62B1F 上白字 = 4.97 ✅),但红底上用黑字要重算(#D62B1F 上黑字 = 4.22 → 正常字号不过)。
  3. 红 + 黑 + 白三色里,"红"不能作为唯一的信息载体(例如"红色=错误/必读"):色盲用户 + 高对比模式会把红压成黑。必须配形状/图标/下划线/文字标签。
  4. 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;
  }
}

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; }
}

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;
}

必须知道的六条

  1. 中文别整包加载:Noto Sans SC / 思源黑体全量数 MB。用 unicode-range 切子集(font-unicode-range caniuse 实测 chrome≥100 / safari≥10 / firefox≥100),或用 pyftsubset/fonttools、Google Fonts 的 &text= 参数现切。
  2. size-adjust 已经是安全项(chrome 92 / ff 92 / safari 17),但 ascent-override / descent-override 在 Safari 仅 TP 可用(MDN BCD 实测 safari = preview)→ 所有"用度量覆盖来消灭 CLS"的方案在 Safari 都会失效,请老老实实给巨字容器预留 min-height 或用 line-height 控制。
  3. 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 必须存在)。
  4. 字重不匹配:拉丁怪诞体常用 800–900,而中文若只有 Regular,混排会明显"中文发虚"。→ 优先选有 7 个字重的思源黑体/Noto Sans SC,或对中文单独用 font-weight: 700 + -webkit-text-stroke 假装加粗(慎用,会糊)。
  5. font-display: swap 是双刃剑:中文 swap 会先闪系统字体(字宽差极大 → 布局跳动)。巨字标题建议 font-display: optional 或 <link rel="preload"> 关键子集。
  6. 标点与字距:构成主义巨字常配极紧字距,但中文的 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 等目录站的逐页核实