使用方法
- 在「名字名单」里一行写一个名字,示例 18 人;抽取时先按行清理空白,再按 UTF-8 字节算哈希,所以同名永远得到同一个颜色。
- 在「取色方式」选口径:默认「名字哈希定色」适合给成员分配固定色;切到「完全随机取色」则每次点一下都换一个色相、饱和度与明度。
- 点「抽取并取色」,或在名单框里按 Ctrl/Cmd+Enter。结果是八格:抽中的名字、色块、HEX、RGB、HSL、OKLCH,以及两个对比度。
- 看对比度两格:对白底与对黑底各给一个比值,其中至少一个达到 4.5:1 才算过正文门槛,状态条会直接写出是白底达标还是黑底达标。
- 「复制结果」拿走八格文本,「复制对照表」按 TSV 贴,「导出对照表 CSV」导 18 行明细,中文用 Excel 打开不乱码。
随机名字取色能解决什么问题
第一个场景是给成员分配固定色。群里十几个人要各有一个专属色,用真随机会每刷一次就换一个色,标签和头像对不上;本页默认把颜色交给名字哈希,所以「张三」永远是 #5DBA2C,谁在什么时候算都一样。
第二个场景是抽签配上颜色。要随机点一个人,还要顺手拿到一个能用的色值,抽一次就同时得到名字和 HEX,不用在抽签工具与取色器之间来回切换。
第三个场景是排版前先验对比度。给名字上色最容易踩的坑是「字色和背景太接近」,本页把两档对比度直接算出来:示例里张三的颜色对白底只有 2.46,远低于 4.5,说明它只能配深色字或深色底;而孙悟空那一档对白底 9.50,放在白底上非常稳。
第四个场景是核对颜色的感知亮度。固定 S=62%、L=45% 之后,18 个人里颜色深浅并不均匀:OKLCH 明度最高的欧阳锋是 0.742,最低的孙悟空只有 0.413。想选一批「看起来一样深」的颜色,就得看 OKLCH 这一格,而不是看 HSL 的 L。
本页只做「一个名字配一个颜色」。要把名单整体随机打乱请用列表随机打乱,要在转盘上抽人请用随机转盘,要按比例分组请用抽奖抽取生成器,要给图片取色请用图片颜色取色——它们不涉及颜色与对比度校验。
哈希定色与对比度校验的原理
先说颜色是怎么定的。哈希选 FNV-1a 的 32 位版本:起始值取 0x811c9dc5,每读一个 UTF-8 字节先异或再乘质数 0x01000193,全程按 32 位取模。把结果对 360 取余就得到色相,再固定饱和度 62%、明度 45%,交给 HSL 到 RGB 的转换公式得到三通道整数。整个过程没有随机数,所以同名恒定。
随机名字取色为什么固定 S=62%、L=45%,而不是让三个分量都随机?因为饱和度与明度随机会让同一批成员色看起来「有的很脏、有的很刺眼」,不利于并列展示。把两项钉死,变化只落在色相上,一批颜色的「重量感」就一致;代价是只有 360 档色相,超过 360 人时会开始出现同色,这也是名称空间的上限。
对比度这一层用的是 WCAG 的相对亮度公式。先把每个通道从 sRGB 值除以 255 归一到 0 到 1,再线性化:小于等于 0.03928 时除以 12.92,大于时取 ((c+0.055)/1.055) 的 2.4 次方;然后按 0.2126、0.7152、0.0722 三个系数加权求和,三个系数之和正好是 1.0000。两个相对亮度相除时各加 0.05:(L1+0.05)/(L2+0.05),大值在分子,结果范围 1 到 21。
OKLCH 用到同一套线性化。把线性 RGB 先转成 Oklab 的 L、a、b 三个分量,再算色度 C 与色相角 H,写成 oklch(L C H)。它由 CSS Color Module Level 4 定义,好处是感知均匀:同样的 L 差值在视觉上看起来差不多,而 HSL 做不到。示例里张三的 HSL 是 hsl(99, 62%, 45%),OKLCH 是 oklch(0.705 0.195 137.3)——同一个颜色两套坐标,色相角一个是 99 度、一个是 137 度,因为两者的色相定义不同。
再说抽取。名册最多 500 行,用 crypto.getRandomValues 取值后对 500 取模会引入偏差,因为 2 的 32 次方除以 500 余 296;本页先丢掉落在余数区间的取值再取模,保证每个人被抽中的概率完全一致。取色相时也一样,360 不能整除 256,所以用 16 位取值加拒绝采样,而不是直接 % 360。
完整示例(数值仅作演示)
随机名字取色在默认设置下(18 人名单、名字哈希定色)打开就是「张三」:#5DBA2C,HSL 是 hsl(99, 62%, 45%),OKLCH 是 oklch(0.705 0.195 137.3)。它的相对亮度是 0.376268,对白底等于 1.05 除以 0.426268,得 2.46;对黑底等于 0.426268 除以 0.05,得 8.53。2.46 不到 4.5,8.53 远超 4.5,所以结论是黑底达标——这个颜色适合做深色底上的文字或色块。
再看几个反差明显的:李四拿到色相 359 的 #BA2C2E,对白底 6.02、对黑底 3.49,白底达标;孙悟空拿到色相 243 的 #332CBA,对白底 9.50、对黑底 2.21,是 18 人里对白底最稳的一个;欧阳锋拿到色相 72 的 #9DBA2C,对白底只有 2.21,是 18 人里最不适合放在白底上的一个。
统计整张表:18 人里对白底达标 9 人、对黑底达标 9 人,正好各半;没有任何一个颜色的两档都不达标。原因是 S=62%、L=45% 已经落在中等偏深的位置,色相只在这条「中等明度带」上滑动,所以要么偏深(能配白底),要么偏亮(能配黑底)。
输入范围与对照表
名单每行一个名字,单行最多 40 个字符,总行数 1 到 500;取色方式两档;色相固定 360 档、饱和度 62%、明度 45%。下表列出 18 人名单的取色结果与对比度。
| 名字 | 色相 | HEX | OKLCH 明度 | 对白底 | 对黑底 | 4.5:1 结论 |
|---|---|---|---|---|---|---|
| 张三 | 99 | #5DBA2C | 0.705 | 2.46 | 8.53 | 黑底过 |
| 李四 | 359 | #BA2C2E | 0.521 | 6.02 | 3.49 | 白底过 |
| 王五 | 33 | #BA7A2C | 0.633 | 3.55 | 5.91 | 黑底过 |
| 赵六 | 74 | #99BA2C | 0.739 | 2.23 | 9.41 | 黑底过 |
| 孙悟空 | 243 | #332CBA | 0.413 | 9.50 | 2.21 | 白底过 |
| 林黛玉 | 213 | #2C6CBA | 0.531 | 5.30 | 3.96 | 白底过 |
| 欧阳锋 | 72 | #9DBA2C | 0.742 | 2.21 | 9.49 | 黑底过 |
| 苏乞儿 | 262 | #602CBA | 0.452 | 8.18 | 2.57 | 白底过 |
| 花木兰 | 322 | #BA2C86 | 0.545 | 5.54 | 3.79 | 白底过 |
| 李慕白 | 313 | #BA2C9B | 0.554 | 5.36 | 3.92 | 白底过 |
| 令狐冲 | 217 | #2C62BA | 0.508 | 5.89 | 3.56 | 白底过 |
| 黄蓉 | 77 | #92BA2C | 0.734 | 2.26 | 9.28 | 黑底过 |
| 韦小宝 | 125 | #2CBA37 | 0.691 | 2.57 | 8.19 | 黑底过 |
| 小龙女 | 348 | #BA2C48 | 0.525 | 5.93 | 3.54 | 白底过 |
| 乔峰 | 122 | #2CBA30 | 0.690 | 2.57 | 8.17 | 黑底过 |
| 段誉 | 157 | #2CBA83 | 0.703 | 2.48 | 8.46 | 黑底过 |
| 虚竹 | 233 | #2C3CBA | 0.434 | 8.53 | 2.46 | 白底过 |
| 张无忌 | 95 | #67BA2C | 0.709 | 2.43 | 8.64 | 黑底过 |
从表里能看出色相与结论的关系:色相落在 210 到 270 的冷色区(孙悟空 243、虚竹 233、林黛玉 213、令狐冲 217、苏乞儿 262)全部是对白底达标,因为这些色相在 sRGB 里天然偏暗;色相落在 70 到 160 的黄绿区(欧阳锋 72、赵六 74、张无忌 95、张三 99、段誉 157)几乎全部是黑底达标,因为它们天然偏亮。
边界与精度说明
先说「HSL 的明度不等于感知亮度」这件事,它是最常见的误读来源。把 HSL 明度固定在 45% 只是数值上的中点,实际亮度随色相大幅波动:纯色的三原色里,绿色的相对亮度是 0.715200、红蓝只有 0.212600 与 0.072200,差距接近十倍。本页示例 18 人的 OKLCH 明度从 0.413 到 0.742,跨度 0.329,就是这条曲线在起作用的证据。
再给三个阈值数字:对白底 3.95 是灰色 #808080(HSL 0,0,50%)的对比度,看着「不深不浅」的纯灰其实还没到 4.5;红色 #FF0000 对白底 4.00,同样不够;黑底那一侧 5.25,勉强够大字号的 3:1。这就是为什么「随便挑个中灰当文字色」经常踩线。
标准阈值分三档:正文文字 4.5:1、大字号文字(约 18.66px 粗体或 24px 常规以上)3:1、图标与边框这类非文本元素 3:1,分别出自 WCAG 2.1 的 SC 1.4.3 与 SC 1.4.11。本页只算颜色本身,不判断你的字号;如果拿到的比值在 3 到 4.5 之间,把它用在大字上通常是安全的。
数值精度方面:线性化的拐点是 0.03928,两侧公式在拐点处连续;三个亮度系数 0.2126、0.7152、0.0722 之和为 1.0000,所以亮度值一定落在 0 到 1。对比度保留两位小数,上下限是 1.00(同色)到 21.00(纯黑对纯白)。十六进制输出固定六位大写,不含 alpha 通道。
关于确定性:哈希模式同名恒定,但不同名字可能撞到同一色相,360 档意味着 500 人名单里一定有重复色(按生日问题,500 人落在 360 档上几乎必然重叠)。要人人不同色,就得把名单压到几十人,或改用「完全随机取色」并在结果里人工核对。
常见问题
为什么同一个名字每次算出来颜色都一样?
因为默认档把色相交给 FNV-1a 哈希,哈希是确定函数:同样的字节序列永远得到同一个 32 位结果,对 360 取余后自然还是同一个色相。这是刻意设计——成员色、标签色需要跨会话保持一致,否则刷新一次整批颜色就变了。
抽中的名字总是同一个人,是随机坏了吗?
不是。打开页面时结果区显示的是名单第一行(示例里的张三),固定不动;只有点「抽取并取色」才会用 crypto.getRandomValues 重新抽。这样首屏永远有内容、也不会在你还没看清设置时就把名字换掉。
对白底和对黑底要两个都过 4.5:1 吗?
不需要,只要你要用的那个背景过线即可。本页给两档是为了让你知道这个颜色适合放在哪种底色上:张三对白底 2.46、对黑底 8.53,说明它只能配深色底;虚竹正好相反,对白底 8.53、对黑底 2.46,适合白底。
OKLCH 和 HSL 的明度为什么对不上?
因为两套坐标系不是一回事。HSL 是 sRGB 的简单重排,它的 L 只表示「从黑到白的中轴位置」,不校正人眼对不同色相的敏感度;OKLCH 建在 Oklab 上,L 是感知亮度。同一个颜色在 HSL 里是 45%、在 OKLCH 里可能是 0.41 也可能是 0.74,后者才是「看起来多亮」。
名单里有重名会怎样?
不会报错,但抽取概率会被重名抬高:如果「张三」出现两次,它被抽中的概率就是别人的两倍,取色结果当然完全相同(同名同色)。想让每人权重一致,先去一遍重再粘进来;要保留重名又要等概率,就按人而不是按行来组织名单。
为什么人数多了颜色会开始重复?
因为色相只有 360 档。按生日问题,只要人数接近几十,出现同色相的概率就迅速上升;500 人名单里几乎必然有大量重复。想要更多区分度,得放开饱和度与明度(本页的「完全随机取色」档会同时随机这三项,可达 1339560 种组合),代价是颜色深浅不再整齐。
算出来的 HEX 能直接用在设计稿里吗?
可以。HEX 是从 HSL 经标准公式转 RGB 再补零成六位大写,与设计工具里手输同一个值等价;OKLCH 那一格也按 CSS Color 4 的写法给出,现代浏览器与设计工具可以直接解析。唯一要注意的是本页不含 alpha,半透明需要你自己补第八位。
颜色和对比度是在服务器上算的吗?
不是。哈希、HSL 转 RGB、sRGB 线性化、相对亮度、对比度、Oklab 转换全在同一段内联脚本里完成,只用 Math 与 TextEncoder,不发网络请求,可以用开发者工具的 Network 面板自查。关掉网络也能正常使用。