“再蓝一点”“颜色太重了”“想要柔和一些”都很常见,但不够明确。你可能想变深,对方却提高了鲜艳程度;两人说的是不同变化。
先分清色相、明度和彩度,再讨论怎样改颜色。 本篇把这三个方向拆开观察。目标不是背一张色环,而是能准确描述两块颜色之间的差别。
四种蓝,差别在哪里?
想象浅蓝衬衫、深蓝封面、鲜艳蓝塑料和偏灰的蓝墙面。它们都可以属于蓝色附近,却并不相同。
这里的四块色样在同一背景上比较。A 与 B 主要展示浅深变化,C 与 D 主要展示偏灰与更鲜明的差别。把它们都称作“不同的蓝”没有错,但还可以说得更具体。
| 维度 | 先用日常语言理解 | 一个容易混淆的说法 |
| 色相 | 偏什么颜色,例如偏青的蓝或偏紫的蓝 | “更蓝”可能是在改色相,也可能是在改彩度 |
| 明度 | 相对有多浅、多深 | 浅蓝不一定比深蓝更鲜艳 |
| 彩度 | 偏离同明度中性色有多远 | 颜色变鲜明不等于它一定变亮 |
这些定义需要放在指定的色彩体系里使用。“饱和度”与“彩度”也不是在所有体系中完全相同的量。
一次只改一个方向
下面采用 OKLCH:L 对应明度,C 对应彩度,H 对应色相。它是一种便于描述和计算的颜色表示。我们只选取显示器能正常显示的蓝色附近的一小段范围。
正在呈现知识画面
把颜色的三种变化分开色样使用 OKLCH 的色相 H、明度 L 与彩度 C。每次只移动一个滑杆。范围限定在可显示的蓝色附近;中性色对照保留 L,把 C 设为 0,并不是截图的灰度转换。
{"id":"color-three-attributes","title":"把颜色的三种变化分开","summary":"色样使用 OKLCH 的色相 H、明度 L 与彩度 C。每次只移动一个滑杆。范围限定在可显示的蓝色附近;中性色对照保留 L,把 C 设为 0,并不是截图的灰度转换。","height":820,"html":"<h2 data-i18n=\"heading\"></h2><p data-i18n=\"intro\"></p><svg class=\"scene\" viewBox=\"0 0 480 260\" role=\"img\" data-i18n-label=\"scene\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"0\" y=\"0\" width=\"480\" height=\"260\" fill=\"#d8d8d8\"/><rect id=\"swatch\" x=\"110\" y=\"30\" width=\"260\" height=\"200\" rx=\"2\"/></svg><label for=\"hue\" data-i18n=\"hue_label\"></label><input id=\"hue\" type=\"range\" min=\"220\" max=\"280\" value=\"250\" step=\"1\"><output id=\"hue-value\" for=\"hue\" class=\"readout\"></output><label for=\"lightness\" data-i18n=\"lightness_label\"></label><input id=\"lightness\" type=\"range\" min=\"45\" max=\"78\" value=\"62\" step=\"1\"><output id=\"lightness-value\" for=\"lightness\" class=\"readout\"></output><label for=\"chroma\" data-i18n=\"chroma_label\"></label><input id=\"chroma\" type=\"range\" min=\"0\" max=\"8\" value=\"6\" step=\"1\"><output id=\"chroma-value\" for=\"chroma\" class=\"readout\"></output><div class=\"controls\" role=\"group\" data-i18n-label=\"choices\"><button type=\"button\" data-mode=\"color\" aria-pressed=\"false\" data-i18n=\"color\"></button><button type=\"button\" data-mode=\"neutral\" aria-pressed=\"false\" data-i18n=\"neutral\"></button></div><div class=\"status\"><p id=\"status\" role=\"status\" aria-live=\"polite\"></p></div><p class=\"readout\" data-i18n=\"note\"></p>","css":"\nbody { padding:22px; }\nh2 { font-size:20px; line-height:1.4; }\np { font-size:16px; line-height:1.65; }\n.scene { display:block; width:100%; height:auto; overflow:hidden; border-radius:4px; background:#e8e4dc; }\n.scene * { transition:none!important; }\n.controls { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:16px 0; }\n.controls button { flex:1 1 auto; min-height:44px; font-size:16px; }\nlabel { display:block; font-size:16px; margin:14px 0 4px; }\ninput[type=range] { width:100%; min-height:28px; }\n.readout { font-size:16px; color:var(--muted); }\n.status { display:grid; border-top:1px solid var(--rule); padding-top:12px; margin-top:16px; }\n.status p { grid-area:1/1; margin:0; }\n.status [aria-hidden=true] { visibility:hidden; }\n@media(max-width:480px) { body {padding:16px 12px;} h2 {font-size:19px;} }\n","js":"const $=s=>document.querySelector(s); const $$=s=>Array.from(document.querySelectorAll(s));\nfunction say(key){$('#status').textContent=viz.t(key);document.body.dataset.state=key;}\nfunction reserve(keys){keys.forEach(k=>{const p=document.createElement('p');p.textContent=viz.t(k);p.setAttribute('aria-hidden','true');$('.status').append(p);});}\nfunction selected(attr,value){$$('button['+attr+']').forEach(b=>b.setAttribute('aria-pressed',String(b.getAttribute(attr)===value)));}\n\nlet mode='color';\nfunction rgb(L,C,H){const a=C*Math.cos(H*Math.PI/180),b=C*Math.sin(H*Math.PI/180);\n const l=(L+.3963377774*a+.2158037573*b)**3,m=(L-.1055613458*a-.0638541728*b)**3,s=(L-.0894841775*a-1.291485548*b)**3;\n return [4.0767416621*l-3.3077115913*m+.2309699292*s,-1.2684380046*l+2.6097574011*m-.3413193965*s,-.0041960863*l-.7034186147*m+1.707614701*s].map(v=>Math.round(255*(v<=.0031308?12.92*v:1.055*v**(1/2.4)-.055)));}\nfunction render(){const L=Number($('#lightness').value)/100,C=Number($('#chroma').value)/100,H=Number($('#hue').value);const values=rgb(L,mode==='neutral'?0:C,H);\n const hex='#'+values.map(v=>v.toString(16).padStart(2,'0')).join('');$('#swatch').setAttribute('fill',hex);\n $('#hue-value').textContent=viz.number(H,0)+'°';$('#lightness-value').textContent=viz.number(L,2);$('#chroma-value').textContent=viz.number(C,2);\n say('s_'+mode);selected('data-mode',mode);document.body.dataset.rgb=values.join(',');document.body.dataset.l=L;document.body.dataset.c=C;document.body.dataset.h=H;\n $('#swatch').setAttribute('data-color',hex);\n}\nreserve(['s_color','s_neutral']);$$('input').forEach(s=>s.oninput=render);$$('button[data-mode]').forEach(b=>b.onclick=()=>{mode=b.dataset.mode;render();});render();\n","audio":false,"strings":{"choices":"比较方式","chroma_label":"彩度 C","color":"显示所选颜色","heading":"变亮,和变鲜艳有什么不同?","hue_label":"色相 H · 蓝色附近","intro":"先只调明度,再恢复到 0.62,只调彩度。比较两个方向的变化;最后试试色相。","lightness_label":"明度 L","neutral":"同 L 的中性色","note":"采用 OKLCH 的有限色域片段,输出为 sRGB。数字不是所有人感觉完全等距的保证;C = 0 时色相不影响显示。","s_color":"L 主要描述浅深,C 描述偏离中性色的程度,H 描述色相方向。一次只改一项,比较会更清楚。","s_neutral":"现在显示相同 L、C = 0 的中性色。调 H 或所选 C 不改变这块对照;改 L 才会改变它。这不是对原色样做亮度测量。","scene":"固定灰背景上的单个可调蓝色色样。"}}
先只提高 L,再恢复原值、提高 C。两种变化给人的感觉不同。最后调整 H,观察蓝色怎样偏向相邻色相。
“同 L 的中性色”会把 C 设为零,但保留当前 L。它帮助理解这个体系里的明度维度,不是把屏幕拍下来后测量物理亮度,也不是证明两块颜色对每个人都完全等亮。当 C 为零时,改变 H 不会改变颜色,因为它已经是中性色。
为什么不直接用调色器里的亮度?
不同调色器可能使用 HSL、HSV 或其他表示。HSL 的 L、HSV 的 V 与这里的 OKLCH L 不同,不能仅因为名称都带“亮”就互换。
例如,把两个不同色相的颜色都设成 HSL 的 50%,并不能保证它们看起来一样明亮。使用颜色工具时,先确认坐标属于哪种体系,再解释数值的意义。本篇不要求记住转换公式,交互已经完成从 OKLCH 到 sRGB 的转换。
完整示范:收到“这个蓝太重了”,究竟该改哪一项?
假设你正在给一个杯子选颜色。客户说“太重”,这个词可能指太暗、太鲜艳,也可能是杯子面积过大。先把模糊描述拆开,不要同时乱动三个滑杆。
图中只改杯身与把手的颜色,背景、叶子、形状和位置固定。四种杯色由同一套 OKLCH 转换生成:A 为 L=0.53、C=0.07、H=240°;B 只把 L 提到 0.75;C 只把 C 降到 0.018;D 只把 H 改到 185°。数值用来隔离变化方向,不是要求你记住这组坐标。
A → B:如果意思是“太暗”,先提高明度。 杯子变浅,和浅背景之间的明暗差减小。它可能显得更轻,但轮廓也可能不够清楚。改完要回看边界,而不是只在调色器里看一个孤立色块。
A → C:如果意思是“太抢眼”,可以先试降低彩度。 杯子更偏灰,却没有把明度坐标一起抬高。灰蓝并不等于浅蓝;把每个颜色都降低彩度,也不一定会得到有层次的画面。
A → D:如果意思是“想偏绿一点”,才是改色相。 这是颜色家族方向的变化。假如原问题是字看不清,绕色相环转一圈却保持近似明暗,未必能解决问题。
四种版本没有统一的美观排名。把它们放回任务里判断:浅色商品图可能选择 B,较克制的插画可能试 C,需要呼应植物的方案可能试 D。每个判断都要带上具体意图与周围关系。
暖色、冷色与中性色怎样用得具体?
红橙黄常被概括为偏暖的家族,蓝及部分蓝绿常被概括为偏冷;但局部比较同样重要。偏紫的蓝与偏绿的蓝放在一起,会产生不同的冷暖判断。不能仅凭“蓝色”二字就解释整张图的感觉。
“中性色”在严格模型中可以指无彩色轴;设计交流里也常把灰米色、灰褐色、很低彩度的蓝灰称作中性色。它们并不一定完全没有色相。米白靠近冷白时会更显暖,蓝灰靠近米白时也更显蓝。挑背景时,低彩度区域的偏色仍然会影响其他颜色。
实际选择可以这样开始:先挑一块偏暖或偏冷的低彩度底色,再把候选主体色放到它旁边比较。这样比“所有白都一样”“中性色不会影响配色”的假设可靠。
三原色为什么会有不同版本?
屏幕主要通过红、绿、蓝光相加形成颜色;彩色印刷常用青、品红、黄并配合黑色油墨。传统绘画教学又常见红、黄、蓝色环,它对颜色家族的比较很直观,但不能把它当作所有显示器和颜料的精确混合公式。
因此,“蓝的补色是什么”要先看你在用哪种色环或混合体系。设计中说蓝橙互补,通常是在讲传统色环附近的色相对比方向;程序把 RGB 分量各自取反,得到的则是另一种数值操作。不能只因两者都叫“补色”,就期待结果完全相同。
颜料还会受具体色料、透明度和底色影响。把屏幕上两个色块并排,并没有模拟它们在调色盘上混合。这里先学会选色和描述,真正混颜料时还需要小样试混。
一张可以反复使用的选色检查单
先写一句具体修改目标,例如“杯子比叶子更浅一点,但保留蓝感”。然后只改相关坐标,将新旧版本并排放在同一背景上,检查对象轮廓和整体主次。若问题没有解决,再判断是否其实应该改面积、位置或周围颜色。
需要匹配真实商品色时,显示器状态、照明、色彩管理和实物打样还会影响结果。本课的屏幕色样适合建立判断方法,不能代替生产中的颜色校对。下一篇会把这些变化用在完整的配色方案里。
换成包装:改色相是否解决了边界问题?
任务是让包装外缘从浅背景里更清楚地显现,同时保留柔和的颜色。A 是现状;B 保持 OKLCH 明度和彩度、只把蓝方向换成绿方向;C 保持蓝方向和彩度、降低明度。选一个优先方案,并比较它的代价。
先判断,再展开图解
C 直接拉开包装与背景的明暗差,边界更明确;代价是包装看起来更深。B 换了颜色家族,却保留近似的浅深关系,边界问题仍在。若品牌要求包装必须很浅,还可另试改变紧邻背景或加边框;那是不同的修改约束。注意这道题判断外缘,深色 TEA 文字原本就清楚。
两个短自检
情境一: 你希望按钮颜色更鲜明,却不想明显改变浅深。应该先试哪个方向?
展开参考思路
在明确的色彩体系里,先保持明度与色相,尝试提高彩度,再放回实际背景中核对效果。显示色域可能限制可用范围;工具数值不是最终观感的替代品。
情境二: 一块灰色的 C 已经是 0,改变 H 后看不出差别。这说明控件坏了吗?
展开参考思路
没有。无彩色没有可见的色相方向;在这个表示里,C = 0 时 H 不影响输出。先增加一点 C,再比较 H 的变化。
回到清楚的描述
下次比较两种颜色,可以先说“它更浅”“它更偏紫”“它更鲜明”。每次尽量说明一个维度,再看几个维度如何一起变化。
可选实践:找同一色相附近的衣物或包装,按浅深排一次,再按柔和到鲜明排一次。两次排序不必相同。
延伸阅读:Colour Literacy:颜色属性、CSS Color 4:Oklab 与 OkLCh。光的相加与颜料的混合属于不同过程,本篇的屏幕色样不承担颜料配方教学。