屏幕上的每一个颜色,背后都是一组数字——不多不少,六个字符。这个看似简单的编码体系,连接着十六世纪数学家发明的计数法、人眼视网膜的感光细胞分布、CRT 显示器残留下来的 gamma 曲线,以及 WCAG 无障碍标准中关于「什么颜色才看得清」的精密计算。
本文从两个具体颜色 #8a939e(冷灰)和 #8a7e72(暖灰)出发,逐层拆解这套编码系统的全部奥秘。
我们日常用十进制(0–9),计算机用二进制(0–1)。十六进制(0–9 + A–F)是连接二者的桥梁:一位十六进制数恰好等于四位二进制数。
| 十进制 | 二进制 | 十六进制 |
|---|---|---|
| 0 | 0000 | 0 |
| 1 | 0001 | 1 |
| 9 | 1001 | 9 |
| 10 | 1010 | A |
| 11 | 1011 | B |
| 12 | 1100 | C |
| 13 | 1101 | D |
| 14 | 1110 | E |
| 15 | 1111 | F |
一位十六进制数最多表示 15(F)。两位十六进制数最多表示 FF = 15×16 + 15 = 255。而 255 恰好是一个字节(8 位二进制 11111111)能表达的最大值。
这意味着:每两位十六进制数,刚好填满一个字节的存储空间。三个颜色通道 × 一个字节 = 总共 24 位,这就是「真彩色(True Color)」的由来——显示器上每个像素的颜色由 24 位数据驱动。
可表达颜色总数:256 × 256 × 256 = 16,777,216 种颜色——超过人眼能区分的极限(约 1,000 万种)。
#RRGGBB 的秘密显示器是自发光设备——它从黑色开始,向每个像素的红、绿、蓝子像素施加电压,让它们以不同强度发光。三种光叠加,形成你看到的颜色。
| RGB 值 | 十六进制 | 结果 | 原理 |
|---|---|---|---|
| (0, 0, 0) | #000000 | 纯黑 | 没有光 |
| (255, 0, 0) | #ff0000 | 纯红 | 只有红光 |
| (0, 255, 0) | #00ff00 | 纯绿 | 只有绿光 |
| (0, 0, 255) | #0000ff | 纯蓝 | 只有蓝光 |
| (255, 255, 0) | #ffff00 | 黄色 | 红 + 绿 |
| (0, 255, 255) | #00ffff | 青色 | 绿 + 蓝 |
| (255, 0, 255) | #ff00ff | 品红 | 红 + 蓝 |
| (255, 255, 255) | #ffffff | 纯白 | 所有光全开 |
# 8a 93 9e
↑ ↑ ↑ ↑
│ │ │ └── 蓝色通道: 9e₁₆ = 158₁₀
│ │ └────── 绿色通道: 93₁₆ = 147₁₀
│ └───────── 红色通道: 8a₁₆ = 138₁₀
└─────────── "井号"标识这是十六进制颜色码
| 格式 | 示例 | 说明 |
|---|---|---|
| 6 位标准 | #8a939e | 最常见,#RRGGBB |
| 3 位缩写 | #fc3 = #ffcc33 | 每两位相同时可缩写,节省三个字符 |
| 8 位带 Alpha | #8a939e80 | 末尾两位是透明度:00=全透明,ff=完全不透明 |
| 4 位缩写+Alpha | #f3c8 = #ff33cc88 | 3 位缩写 + 1 位透明度 |
⚠️ 3 位缩写只能在每对数字相同时使用。
#aabbcc→#abc✔,但#8a939e不能缩写为#839(因为 8a ≠ 83,39 ≠ 93)。
一个反直觉的事实:#808080(RGB 128, 128, 128)的亮度不是纯白 #ffffff 的一半。128 ÷ 255 ≈ 50%,但它的视觉亮度只有约 21.4%。
这是因为人类对光的感知是非线性的,显示器本身也有自己的非线性响应曲线。sRGB 标准定义了一条gamma 校正曲线来协调这个问题。
黑白渐变:#000000 → #ffffff——视觉上均匀,但对应的物理亮度并非线性
sRGB 中存储的值(就是 hex 里的数字)是经过 gamma 编码的。要获得真实的物理亮度(线性亮度),需要经过转换:
对于每个通道值 c(范围 0-255):
先归一化:c' = c / 255
如果 c' ≤ 0.04045:
c_linear = c' / 12.92
否则:
c_linear = ((c' + 0.055) / 1.055) ^ 2.4
这个转换的实质是:把 8 位值中更多的精度分配给人眼更敏感的区域(暗部)。
| 颜色 | sRGB 值 | 物理亮度 | 你看到的感觉 |
|---|---|---|---|
#ffffff | R=1.0, G=1.0, B=1.0 | 100% | 最亮 |
#808080 | R=0.5, G=0.5, B=0.5 | 21.4% | 中灰 |
#404040 | R=0.25, G=0.25, B=0.25 | 5.0% | 深灰 |
#000000 | R=0, G=0, B=0 | 0% | 最暗 |
即使在线性空间,人眼对红、绿、蓝的敏感度也完全不同。绿色通道占了视觉亮度的绝大部分:
L = 0.2126 × R_linear + 0.7152 × G_linear + 0.0722 × B_linear
为什么绿色权重这么高?这是进化的结果——在自然环境中,人类的视觉系统演化出了对光谱中段(黄-绿)最敏感的响应,因为这对应着阳光最强的波段。
这意味着:改动 hex 中的绿色通道(中间两位),对颜色明暗的影响最大;改动蓝色通道(最后两位)影响最小。
以 #8a939e 为例计算相对亮度:
R_linear = linearize(138/255 = 0.541) = 0.259
G_linear = linearize(147/255 = 0.576) = 0.298
B_linear = linearize(158/255 = 0.620) = 0.348
L = 0.2126 × 0.259 + 0.7152 × 0.298 + 0.0722 × 0.348
= 0.055 + 0.213 + 0.025
= 0.293
这个 0.293 的含义:#8a939e 的亮度约等于纯白色的 29.3%。
十六进制只是 RGB 的一种书写方式。同样的颜色信息,可以用完全不同的坐标系来表达。
| 模型 | 坐标系 | 对人类的友好度 | 主要用途 |
|---|---|---|---|
| RGB | 直角坐标 (R, G, B) | ★☆☆☆☆ | 硬件直通、CSS 标准 |
| HEX | RGB 的紧凑十六进制 | ★☆☆☆☆ | 网页设计、工具间交换 |
| HSL | 圆柱坐标 (H, S, L) | ★★★★☆ | 设计师调色、程序化操作 |
| HSV/HSB | 圆柱坐标 (H, S, V) | ★★★★☆ | 拾色器(Photoshop/Figma) |
| OKLCH | 圆柱坐标 (L, C, H) | ★★★★★ | 现代设计系统、CSS Color Level 4 |
| 分量 | 范围 | 含义 |
|---|---|---|
| Hue(色相) | 0°–360° | 色环上的角度:0°=红、120°=绿、240°=蓝、60°=黄、180°=青、300°=品红 |
| Saturation(饱和度) | 0%–100% | 色彩的鲜艳程度:0%=灰色、100%=最饱和 |
| Lightness(明度) | 0%–100% | 明暗程度:0%=纯黑、50%=纯色最饱满、100%=纯白 |
将 #8a939e 转为 HSL:
#8a939e → R=138, G=147, B=158
→ H = 210°(蓝-青区域)
→ S = 9.4%(极低,接近灰色)
→ L = 58.0%(中明度,偏亮)
结果:hsl(210°, 9.4%, 58.0%)
这解释了为什么 #8a939e 是一块冷灰——色相指向蓝青方向(210°),但饱和度极低(9.4%),所以只是带了一丝蓝味的灰色。
同样计算 #8a7e72:
#8a7e72 → R=138, G=126, B=114
→ H = 30°(橙-黄区域)
→ S = 9.7%(同样极低)
→ L = 49.4%(略低于上一块灰)
结果:hsl(30°, 9.7%, 49.4%)
HSL 的好处在此一目了然:不用看具体数字,只看 H 值就知道冷暖——H=210° 是冷的,H=30° 是暖的。
#8a939e → hsl(210°, 9.4%, 58%) ❄️ 冷灰
#8a7e72 → hsl(30°, 9.7%, 49.4%) 🔥 暖灰
HSV 和 HSL 的关键区别在第三个维度。在 HSV 中,Value=100% 时是最鲜艳的纯色(不是白色);要到白色需要把饱和度降到 0%。你每天在 Photoshop 或 Figma 的方形色板里拖取颜色时,操作的就是 HSV 空间。
实用区别:HSL 更适合程序化调色("把这个明度提高 10%"),HSV 更适合视觉选择(在色板中直观定位)。
HSL 有一个严重问题:等量明度 ≠ 等量感知亮度。一个黄色在 50% L 时看起来比蓝色亮得多——这被称为 Helmholtz–Kohlrausch 效应。
OKLCH 由 Björn Ottosson 在 2020 年设计,已原生支持于 CSS Color Level 4,并被 GitHub Primer、Atlassian、BBC 等前端团队采用。同样是 50% 的 L,黄色和蓝色看起来确实一样亮——这对设计系统中的一致性至关重要。
💡 如果你在建设需要跨色相保持视觉一致的设计系统,OKLCH 是比 HSL 好得多的选择。
oklch(L C H)用感知明度替代了 HSL 的数学明度,使不同色相之间的亮度真正可比。
| 方案 | 色环关系 | 效果 | 适合场景 |
|---|---|---|---|
| 单色 (Monochromatic) | 同色相,变 S 和 L | 统一、干净、克制 | 极简设计、内容型界面 |
| 类似色 (Analogous) | 色环上相邻(±30°) | 和谐、柔和、自然 | 品牌色、背景、大面积色块 |
| 互补色 (Complementary) | 色环上 180° 对立 | 高对比、有冲击力 | 按钮高亮、信息图表强调 |
| 分裂互补 (Split-Complementary) | 基准色 + 互补两侧(150°+210°) | 对比但柔和 | 需要强视觉但不刺眼的设计 |
| 三等分 (Triadic) | 120° × 3 | 平衡、活泼、丰富 | 多彩品牌、儿童产品 |
#8a939e 构建调色板单色调色板(保持 H=210°,只调 L 和 S):
#6b7685 —— 更暗、饱和
hsl(210°, 12%, 47%)
#8a939e —— 基准色
hsl(210°, 9%, 58%)
#a8b1b8 —— 更亮
hsl(210°, 7%, 69%)
#cdd3d8 —— 更更亮(接近白色)
hsl(210°, 5%, 82%)
有趣的事情出现了——#8a7e72 的色相 H=30° 与 #8a939e 的 H=210° 恰好相差 180°。它们是互补色对。虽然在 UI 中它们看起来只是两块灰色,但一块偏冷一块偏暖,会产生微妙的冷暖对比张力——这就是高级配色中说的高级感。
60-30-10 黄金比例:60% 主色 #8a939e(背景)+ 30% 辅色(卡片/侧栏)+ 10% 强调色(按钮/链接)。大多数配色失败不是因为颜色选错了——而是比例用错了。
| 属性 | #8a939e | #8a7e72 |
|---|---|---|
| HEX | #8a939e | #8a7e72 |
| RGB | rgb(138, 147, 158) | rgb(138, 126, 114) |
| HSL | hsl(210°, 9.4%, 58.0%) | hsl(30°, 9.7%, 49.4%) |
| HSV | hsv(210°, 12.7%, 62.0%) | hsv(30°, 17.4%, 54.1%) |
| OKLCH | oklch(61.6%, 0.016, 249°) | oklch(54.0%, 0.022, 64°) |
| 相对亮度 | 0.293 | 0.243 |
| 色温 | ❄️ 冷(蓝青) | 🔥 暖(橙黄) |
| 饱和度 | 极低(9.4%) | 极低(9.7%) |
| 明度 | 中高(58%) | 中等(49.4%) |
| 感受 | #8a939e | #8a7e72 |
|---|---|---|
| 像什么 | 阴天天空、不锈钢、混凝土 | 砂石泥土、旧纸张、亚麻布料 |
| 传达 | 理性、克制、冷淡、工业感 | 温暖、自然、质朴、手作感 |
| UI 背景 | SaaS 后台、金融、科技感布局 | 内容型网站、博客、暖色品牌 |
| 文字色 | 次要信息、禁用态、帮助文字 | 正文辅助色(搭配米色/棕色主题) |
| 搭配 | 白色、蓝/青色、银灰 | 米色、棕色、木色 |
#8a939e 做文字的可行性(对比度检测)将 #8a939e(L=0.293)放在纯白背景 #ffffff(L=1.0)上:
(1.0 + 0.05) / (0.293 + 0.05) = 1.05 / 0.343 = 3.06:1
3.06:1 < 4.5:1 → ❌ 不满足 WCAG AA 普通文本标准。仅可用于大标题(≥18pt 或 ≥14pt 粗体)。
要让 #8a939e 达到 AA 标准,需降低明度。在 HSL 中保持 H=210°,S=9.4%,将 L 降到约 46%:
#737c87 —— 对比度约 4.6:1 ✔ 满足 AA
对比度 = (L_亮 + 0.05) / (L_暗 + 0.05)
其中 L 是相对亮度(第三章计算出的值)。结果范围 1:1(相同颜色)到 21:1(纯黑对纯白)。
| 标准 | 要求 | 应用场景 |
|---|---|---|
| AA 普通文本 | ≥ 4.5:1 | 正文、按钮文字、表单标签 |
| AA 大文本 | ≥ 3:1 | 标题(≥18pt 或 ≥14pt 粗体) |
| AAA 普通文本 | ≥ 7:1 | 高可读性要求(医疗/政务等) |
| AAA 大文本 | ≥ 4.5:1 | 大标题的高标准 |
| 非文本对比度 | ≥ 3:1 | 图标、输入框边框、焦点环 |
#888 在白底的对比度只有 3.54:1——远不达标#d4d4d4 在白底上只有 1.6:1,远不达标不需要每次都查表,记住五个锚点就够用了:
| 十六进制 | 十进制 | 亮度感觉 |
|---|---|---|
00 | 0 | 全关 — 纯黑 |
40 | 64 | 暗 |
80 | 128 | 中灰 |
BF | 191 | 亮 |
FF | 255 | 全开 — 最亮 |
看到 hex 的时候,每两位对着这个区间估一下:
#a0b0c0
│ │ │
│ │ └─ c0 ≈ 192,亮蓝
│ └──── b0 ≈ 176,中亮绿
└─────── a0 ≈ 160,中亮红
→ 三通道都没拉满,红略低于绿略低于蓝,亮而且偏冷。
| 工具 | 用途 |
|---|---|
| Coolors | 一键生成配色方案,锁定基准色探索和谐色 |
| Adobe Color | 多种和谐规则 + 无障碍检测 |
| WebAIM Contrast Checker | WCAG 对比度精确计算 |
| ColorUI Contrast | 同时显示 WCAG 和 APCA 两项对比度 |
| Color Lab | HEX/RGB/HSL/HSV/CMYK/OKLCH 全格式互转 |
| 数码测色计(macOS 自带) | ⌘⇧L 锁定颜色,格式可设为十六进制 |
| Chrome DevTools | Elements → Styles 面板点击色块即可编辑和预览 |
/* 用 CSS 自定义属性定义色彩系统 */
:root {
/* 冷灰色阶 */
--gray-cool-400: #8a939e;
/* 暖灰色阶 */
--gray-warm-400: #8a7e72;
/* 在令牌层级验证对比度 */
--text-body: #333;
--text-muted: #6f7a86;
/* 语义色 */
--color-primary: #3b82f6;
--color-accent: #e67e22;
}
色彩令牌的好处:你只需要在一个地方验证对比度,所有用这个令牌的组件自动安全。
| HEX | 名称 | HEX | 名称 |
|---|---|---|---|
#000000 | 纯黑 | #ffffff | 纯白 |
#ff0000 | 纯红 | #00ff00 | 纯绿 |
#0000ff | 纯蓝 | #ffff00 | 纯黄 |
#ff00ff | 品红 | #00ffff | 青色 |
#808080 | 中灰 | #c0c0c0 | 银灰 |
#800000 | 栗色 | #008000 | 深绿 |
#000080 | 藏蓝 | #ff6600 | 橙色 |
#800080 | 紫色 | #8a939e | 冷灰 |
#8a7e72 | 暖灰 |
| 问题 | 答案 |
|---|---|
#RRGGBB 是什么? | 红/绿/蓝各两位十六进制,范围 00–ff |
| 能表示多少种颜色? | 256³ = 16,777,216 |
| 三值越接近意味着什么? | 饱和度越低,颜色越灰 |
| 哪个通道偏高决定什么? | 颜色偏向该色相(冷/暖) |
#8a939e 是什么? | 冷灰,H=210°,R<G<B,像不锈钢 |
#8a7e72 是什么? | 暖灰,H=30°,R>G>B,像砂石 |
| 为什么 128 不是 50% 亮度? | sRGB 用了 gamma 编码,128 物理亮度约 21% |
| 绿色通道为什么特殊? | 人眼对绿最敏感,亮度公式中 G 占 71.5% 权重 |
| 什么比 HSL 更好? | OKLCH——等量 L 在不同色相下感知一致 |
| 文字颜色 AA 标准? | 4.5:1 对比度(大文本 3:1) |
color(display-p3 ...) 已可在现代 CSS 中使用