顆粒漸層 是做什麼的?
平滑的數位漸層看起來很「電腦化」。細微的噪點層能讓它們呈現印刷或底片質感,並隱藏條帶(漸層從一個8位元色彩層級過渡到下一個時出現的可見條紋)。
你完成所有工作。使用者只需觀看並選擇。 絕對不要詢問關於混合模式、不透明度或數值的問題。使用者只做三種決定,別無其他:
- 哪些背景(僅當你掃描了整個網站時)。
- 是否先看前後對比,或直接套用。
- 在預覽中哪個選項看起來最好。
如何思考
-
顆粒是紋理,不是色彩。 它不能變亮、變暗或染色。噪點以中灰色為中心,因此亮度偏移應接近0。它不能用於純黑或純白,報告會說明原因。
-
測量可見部分,而非不透明度。 可見顆粒是L*(CIELAB亮度,0–100)的擴散範圍,且L*是感知性的,因此相同數值在任何顏色上看起來都差不多。低於約0.45時沒有人能看見。目標值為Subtle / Medium / Strong分別對應0.5 / 0.8 / 1.4。
-
均勻分佈在明暗漸層上也有效。 Overlay會將大部分顆粒集中在較亮的部分。Even則選擇(通常為柔光)能更均勻分佈顆粒的混合模式。人們通常偏好這個。
-
顆粒屬於背景。 它位於背景正上方,在所有其他元素之下,並跟隨背景移動。如果背景淡入,顆粒也會隨之淡入。
-
它適應每位訪客的螢幕。 網站無法區分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個項目為一組詢問多選問題。
如果沒有該工具,請要求他們回覆「all」或數字。
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-<option>.png:
- 完整的前後對比
- 放大的細節
- 相同細節,但對比度被拉伸,使條帶顯示為條紋,顆粒顯示為噪點
- 測量數值
將推薦的選項發送給使用者(如果你有檔案傳送工具則使用它;否則提供路徑)。這是變更真實存在的證據。
直接套用
先拍攝基準圖片和照片,以便稍後檢查和顯示結果:
node <技能>/scripts/shoot.mjs --url http://localhost:3000/ --selector ".hero" --option recommended --out ./grain-shots
它會為每張圖片列印一行(顆粒、亮度、條紋寬度),並在 <out>/<selector>/ 目錄下寫入 report.json(報告、每個選項的CSS、推薦選項)和 compare-<option>.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: <option> 以及每個背景的外觀,你可以將其傳送給 node <skill>/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 的子元素。 |
| 純黑或純白 | Overlay和soft-light無法在那裡添加顆粒,因此它會使用screen或multiply,並帶有微小的亮度偏移,並且會說明原因。 |
| 跨漸層的顆粒不均勻 | 如果Even明顯更均勻,則推薦Even。當Even與Medium相同時隱藏Even。 |
| 高條帶風險 | 說明所選顆粒是否會打散條紋。Strong效果更強。 |
| 同一背景中的舊噪點層 | 取代它。如果舊噪點在其他地方(偽元素),則說明要移除它。 |
| 在WebGL/canvas場景中繪製的背景部分(3D地面、著色器背景) | canvas後方的CSS顆粒無法觸及它,因此canvas部分在顆粒化的天空旁邊看起來平滑或有斑點。你 添加它:在該材質的片段著色器中,在色彩空間轉換之後,於螢幕空間中柔光混合相同的噪點瓷磚(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使用一個自訂屬性。 如果多個規則使用同一個,請定義一次。
- 如果報告列出「頂部淡入效果」, 如所述為每個淡入效果提供相同的顆粒,否則在其最深處會再次出現條帶。
- 移除任何臨時內容(預覽標籤、
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螢幕和高對比度設定,並在列印時關閉。如果報告指出該目標尚未經由目視確認,請簡短說明。
後續調整
- 「太多」或「看不見」: 移動一個層級。
-
…
[為翻譯而截斷]