颗粒渐变 是做什么的?
平滑的数字渐变看上去很“计算机化”。一层精细的噪点能让它们呈现印刷品或胶片质感,同时还能隐藏色带(8 位颜色从一个等级过渡到另一个等级时出现的可见条纹)。
您负责完成所有工作。用户只需查看并选择。 永远不要询问混合模式、不透明度或数值。用户只需做三种决定,其他一概不问:
- 哪些背景(仅当您扫描了整个站点时)。
- 是否先查看前后对比,还是直接应用。
- 在预览选择中,哪个效果最好。
思考方式
-
颗粒是纹理,不是颜色。 它不能使图像变亮、变暗或着色。噪点以中灰色为中心,因此亮度变化应接近 0。它不能用于纯黑或纯白,报告中会注明这一点。
-
测量可见部分,而不是不透明度。 可见颗粒对应 L*(CIELAB 亮度,范围 0–100)的分布,L* 是感知性的,因此相同的数值在不同颜色上看起来大致相同。低于约 0.45 时,几乎无法察觉。目标是微弱 / 中等 / 强烈分别为 0.5 / 0.8 / 1.4。
-
在从亮到暗的渐变上使用均衡模式。 覆盖模式会将大部分颗粒集中在较亮部分。均衡模式(通常是柔光)则能更均匀地分布颗粒。人们通常更偏好它。
-
颗粒属于背景。 它位于背景的正上方,在所有其他内容之下,并随背景移动。如果背景淡入,颗粒也会随之淡入。
-
它适应每位访客的屏幕。 网站无法区分 OLED 和 LCD,但 CSS 可以识别 HDR 屏幕(大多数 OLED 手机、XDR 笔记本)和高对比度设置。CSS 包含以下媒体查询:
- 深色背景在 HDR 屏幕上颗粒稍少
- 高对比度设置下颗粒更少
- 打印时关闭颗粒
全部由 CSS 实现,真实站点无需脚本。
-
跳过颗粒无法改善的情况:
- 小元素(按钮、徽章、图标)
- 渐变文字
- 照片上的透明遮罩和淡入
- 条纹和方格图案
1. 用户以哪种方式提出需求?
2a. 查找单个背景
找到实际绘制背景的元素。检查:
- 元素本身及其
::before和::after - 元素内部或后方的全尺寸图层(区块通常通过独立的绝对定位
<div>获取颜色)
使用浏览器工具,列出候选元素:
[...document.querySelectorAll('#section, #section *')].flatMap(e => [null, '::before', '::after'].map(p => [e, p, getComputedStyle(e, p)]))
.filter(([, p, c]) => (!p || c.content !== 'none') && (c.backgroundImage !== 'none' || c.backgroundColor !== 'rgba(0, 0, 0, 0)'))
.map(([e, p, c]) => `${e.tagName.toLowerCase()}${e.id ? '#' + e.id : ''}.${[...e.classList].join('.')}${p || ''} | ${c.position} | opacity ${c.opacity} | ${(c.backgroundImage !== 'none' ? c.backgroundImage : c.backgroundColor).slice(0, 80)}`)
如果没有浏览器,请阅读 CSS。无论哪种方式,在 CSS 中搜索该背景的其他版本:媒体查询(手机布局通常会更换渐变)和深色模式规则。在步骤 5 中会用到它们。
然后转到 步骤 3。
2b. 扫描整个站点
node <本技能文件夹>/scripts/scan.mjs <项目文件夹>
它会在大约一秒内读取样式表(规则、媒体查询、自定义属性)、标记和组件(Tailwind 渐变类、内联样式、CSS-in-JS)。将结果分为四组:
- 好的候选: 大面积背景。
- 值得一看: 代码中无法确定大小。
- 已有颗粒。
- 跳过, 并注明原因。
它还会列出每个样式表加载自哪些页面。添加 --json 以获取完整数据。
自己整理“值得一看”的项。 在展示列表之前,根据您的观察进行排序。使用浏览器工具在页面上测量其大小。否则阅读标记。将每一项移到“好的候选”或“跳过”。不要向用户发送您本可以检查的列表。
然后展示列表, 简短,每项一行,用通俗语言表达,按页面分组。例如:
我找到了 6 个可以添加颗粒的背景:
- 首页,导览区块: 淡入的深色渐变
- 首页,主视觉: 深色径向光晕
- “可持续发展”页,页眉: 绿黑渐变
- “招聘”页,“此处制造”横幅: 橙黑渐变
跳过 12 个:按钮、渐变文字、照片遮罩和条纹图案。 “报价”页面已有颗粒,但数量太少无法看到,因此我会重做。
然后让他们选择。 如果您有多选题工具(如 Claude Code 中的 AskUserQuestion),请使用它:
- 询问“哪些背景应该添加颗粒?”并将 全部添加(推荐) 放在首位。
- 对于最多 3 个其他项,将每个列为一个选项,并启用多选。
- 如果超过 4 个,先询问“全部添加,还是选择?”;如果回答“选择”,则每次以最多 4 项进行多选提问。
如果没有该工具,请让他们回复“全部”或数字。
3. 询问:前后对比,还是直接应用?
对每个选中的背景统一询问:“您想先看到前后对比效果,还是直接为每个应用最佳效果?”如果有多选题工具,请使用它,选项为 先给我看看(推荐) 和 直接应用。
下面的工具需要 Node 22+ 和机器上的 Chrome、Chromium、Edge 或 Brave(自动查找;CHROME_PATH 可覆盖)。它们以无头模式打开页面,因此站点必须可达:正在运行的开发服务器、测试 URL,或用于纯 HTML 的 file://。不会向站点添加任何内容。
4. 展示前后对比
先给我看看:审阅页面
在后台运行它(它会等待用户),每个页面使用一个 --url,后跟该页面的选择器:
node <技能>/scripts/review.mjs --url http://localhost:3000/ --selector ".hero" --selector ".footer-band" \
--url http://localhost:3000/about --selector ".about-header"
- 它会自动截图。 对于每个背景,它会拍摄页面当前状态以及每种选项下的照片,还包括 HDR 屏幕和高对比度设置下的效果。每个页面大约需要 10–30 秒。
- 然后它会打开一个本地审阅页面 并打印其地址;同时将链接提供给用户。
- 每个背景会显示一个卡片,包含:
- 前后对比滑块
- 色带放大,可放大色带最明显的区域(缩小的图片中细颗粒不可见)
- 以标签页形式展示选项,推荐选项标有星号
- 屏幕切换
- 测量数值和包含报告的“原因”
- “完成,发送我的选择” 会将选择直接发送回来。无需复制粘贴。
用一句话告诉他们该做什么:“拖动每张图片,尝试放大,为每个背景选择一项,然后按完成。”当命令退出时,输出包含选择结果、每个背景对应的 CSS,以及每个背景的基准文件夹,用于步骤 7 中的检查。
同时在聊天中展示一张图片。 每个基准文件夹包含 compare-<选项>.png:
- 完整的前后对比
- 放大的细节
- 同一细节经过对比度拉伸,使色带显示为条纹、颗粒显示为噪点
- 测量数值
将推荐的那个发送给用户(如果有文件发送工具则使用它;否则提供路径)。这是效果真实的证据。
直接应用
首先拍摄基准和照片,以便后续检查和展示:
node <技能>/scripts/shoot.mjs --url http://localhost:3000/ --selector ".hero" --option recommended --out ./grain-shots
它会为每张照片输出一行信息(颗粒、亮度、条纹宽度),并将 <出>/<选择器>/ 写入 report.json(报告、每种选项的 CSS、推荐选项)和 compare-<选项>.png。使用 report.json 中的推荐 CSS。
没有 Chrome,或站点无法通过无头模式访问
退回到页面内预览:将 dist/grain-page.js 复制到站点自有脚本旁边(检查其是否可加载,状态码 200 而非 404),添加 <script src="/js/grain-page.js" data-grain=".hero | .footer" defer></script>,并让用户使用 ?grain 参数打开页面。它会在真实页面上显示相同的选项,并带有一个可拖动的滑块;复制选择 会复制 grain: <选项> 以及每个背景的外观,您可以将其通过管道传递给 node <技能>/scripts/grain.js --look - 以生成 CSS。之后移除标签和文件。
如果完全没有浏览器,请自行编写外观并在其上运行 grain.js:
{ "selector": ".hero", "kind": "gradient", "shape": "linear",
"colours": [{ "colour": "#323435", "pos": 0 }, { "colour": "#141617", "pos": 1 }],
"lengthPx": 900, "background": "linear-gradient(...)", "behind": "#ffffff",
"solidBase": true, "position": "relative", "freePseudo": "::after", "moves": null }
或 node grain.js --colours "#323435,#2a2c2d@24%,#141617" --length 900 --selector ".hero" [--shape radial] [--fade-over "#fff"] [--option even]。
引擎自动决定,您无需操心
| 情况 | 操作 |
|---|---|
| 元素上的渐变或纯色 | 单层: 噪点成为元素的顶层背景层(使用 background-blend-mode),保存在 --grain 自定义属性中。在每个背景列表中添加一个值,因此页面自身的大小、位置和混合保持不变。不会覆盖文字。 |
| 背景淡入 | 同一单层,因此颗粒随之淡入。报告会给出淡入各阶段的颗粒情况。 |
| 透明渐变,下方无实色 | 使用自身图层(一个空闲的 ::after/::before,或一个子元素),以便与穿透显示的内容混合,而不是变灰。 |
| 照片或图像背景 | 一个空闲的伪元素,如果两者都被占用则使用子元素。 |
<img>/<video> 填充元素,或伪元素上的背景 | 在隔离宿主中添加 z-index: -1 的子元素。 |
| 纯黑或纯白 | 覆盖和柔光无法在此处添加颗粒,因此使用屏幕或正片叠底,并带有轻微亮度偏移,并在报告中说明。 |
| 跨渐变颗粒不均匀 | 如果均衡模式明显更均匀,则推荐使用。当它与中等相同时,均衡模式会被隐藏。 |
| 色带风险高 | 说明所选颗粒是否能打碎条纹。强烈模式效果更强。 |
| 同一背景中已有旧噪点层 | 替换它。如果旧噪点在其他位置(例如伪元素),说明需要移除它。 |
| WebGL/Canvas 场景中的部分背景(3D 地面、着色器背景) | 画布后的 CSS 颗粒无法到达画布内部,因此画布部分在颗粒天空旁会显得平滑或斑驳。您 需要添加:在该材质的片段着色器中,在颜色空间转换之后,使用屏幕空间中的同一噪点瓦片进行柔光混合(gl_FragCoord.xy / tilePx,tile = 200 × 渲染器像素比)。从页面的 --grain 自定义属性中读取瓦片和数量,以便手机、HDR 和高对比度的数量随之变化,并在窗口大小变化时重新读取。通过渲染一帧并读取像素来测量。 |
| HDR 屏幕、高对比度、打印 | @media (dynamic-range: high) 和 @media (prefers-contrast: more) 为这些屏幕重新计算数量,使用相同的混合模式。@media print 关闭颗粒。如果规则结果相同,则省略。 |
颜色根据其在渐变中的覆盖比例进行加权。细小的亮点不会像大面积深色区域那样被重视,因此同一区块的手机版和桌面版会得到相同的处理。
5. 应用
- 将每个 CSS 块放置在其背景定义的位置,并附上注释。
- 保留项目自身的背景表达式。 引擎基于计算值工作,因此在输出重复长解析渐变的地方,请放回
var(--slate)或原始的linear-gradient(...)。 - 处理每个背景的所有版本(手机版、深色模式)。单层 CSS 放在同一媒体查询内的同一选择器上。如果不同,使用
--phone或--colours测量各个版本。 - 子元素方法: 在注释指定的位置添加
<div class="grain-layer" aria-hidden="true"></div>(在组件中,在其标记内)。 - 对重复的噪声 URL 使用一个自定义属性。 如果多个规则使用同一个 URL,只需定义一次。
- 如果报告列出“顶部淡入”, 请为其添加文中描述的相同颗粒,否则在最暗处会再次出现色带。
- 移除所有临时内容(预览标签、
grain-page.js)。
6. 每次都要检查
在宣布完成之前,将每个背景与其基准进行比较:
node <技能>/scripts/check.mjs --url http://localhost:3000/ --selector ".hero" --baseline <基准文件夹> [--option even]
它会再次拍摄页面照片,并为以下各项输出 PASS/FAIL:
- 颗粒图层 已出现在页面中(CSS 已加载并在正确的选择器上)。
- 页面上没有新错误。
- 颗粒量 接近预期值。
- 亮度 未发生变化。
- 条纹 变窄了。
- 背景外无变化。
- 没有元素移动或改变大小。
它会写入 check.png,显示之前与现在的对比。出现任何 FAIL 时,请修复问题并重新运行检查; 不要在失败时报告成功。如果某个 FAIL 无法修复,请准确告知用户是哪个检查失败以及原因。
7. 报告
每个背景用一两句话说明,或针对整个站点使用简短列表:背景是什么、选择了什么以及原因。附上检查的测量结果(例如“颗粒 0.83 L*,条纹 80px → 0.7px,其他无变化”)并发送 check.png 或 compare 图片。说明一次该颗粒会适应 HDR 屏幕和高对比度设置,并在打印时关闭。如果报告指出对于该类型的背景,目标尚未通过目视确认,请简要说明。
后续调整
- “太多了”或“看不见”: 调整一个级别。
*…
[已截断,用于翻译]*