随机名字取色

从名单里随机抽一个名字,再给它配一个颜色:默认按 FNV-1a 哈希定色相,同名永远同色;也能切成完全随机。结果同时给出 HEX、RGB、HSL 与 OKLCH,并用 WCAG 相对亮度公式算出对白底与黑底的对比度,直接标出有没有过 4.5:1。

抽中的名字张三
色块
HEX#5DBA2C
RGB93, 186, 44
HSLhsl(99, 62%, 45%)
OKLCHoklch(0.705 0.195 137.3)
对白底对比度2.46
对黑底对比度8.53

「张三」→ #5DBA2C(H=99 S=62% L=45%);相对亮度 0.376268;对白底 2.46,对黑底 8.53(4.5:1 门槛),黑底达标。

名字取色与对比度对照表(18 行演示值,默认显示 12 行)
名字色相HEXOKLCH 明度对白底对黑底4.5:1 结论
张三99#5DBA2C0.7052.468.53黑底过
李四359#BA2C2E0.5216.023.49白底过
王五33#BA7A2C0.6333.555.91黑底过
赵六74#99BA2C0.7392.239.41黑底过
孙悟空243#332CBA0.4139.502.21白底过
林黛玉213#2C6CBA0.5315.303.96白底过
欧阳锋72#9DBA2C0.7422.219.49黑底过
苏乞儿262#602CBA0.4528.182.57白底过
花木兰322#BA2C860.5455.543.79白底过
李慕白313#BA2C9B0.5545.363.92白底过
令狐冲217#2C62BA0.5085.893.56白底过
黄蓉77#92BA2C0.7342.269.28黑底过

表内 18 行是「名字哈希定色」口径下的固定演示值(S=62%、L=45% 固定),不随上方「完全随机取色」档变化;18 人里对白底达 4.5:1 的 9 人、对黑底达标的 9 人,正好各半。

使用方法

  1. 在「名字名单」里一行写一个名字,示例 18 人;抽取时先按行清理空白,再按 UTF-8 字节算哈希,所以同名永远得到同一个颜色。
  2. 在「取色方式」选口径:默认「名字哈希定色」适合给成员分配固定色;切到「完全随机取色」则每次点一下都换一个色相、饱和度与明度。
  3. 点「抽取并取色」,或在名单框里按 Ctrl/Cmd+Enter。结果是八格:抽中的名字、色块、HEX、RGB、HSL、OKLCH,以及两个对比度。
  4. 看对比度两格:对白底与对黑底各给一个比值,其中至少一个达到 4.5:1 才算过正文门槛,状态条会直接写出是白底达标还是黑底达标。
  5. 「复制结果」拿走八格文本,「复制对照表」按 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 人名单的取色结果与对比度。

名字取色与对比度对照表(18 行演示值)
名字色相HEXOKLCH 明度对白底对黑底4.5:1 结论
张三99#5DBA2C0.7052.468.53黑底过
李四359#BA2C2E0.5216.023.49白底过
王五33#BA7A2C0.6333.555.91黑底过
赵六74#99BA2C0.7392.239.41黑底过
孙悟空243#332CBA0.4139.502.21白底过
林黛玉213#2C6CBA0.5315.303.96白底过
欧阳锋72#9DBA2C0.7422.219.49黑底过
苏乞儿262#602CBA0.4528.182.57白底过
花木兰322#BA2C860.5455.543.79白底过
李慕白313#BA2C9B0.5545.363.92白底过
令狐冲217#2C62BA0.5085.893.56白底过
黄蓉77#92BA2C0.7342.269.28黑底过
韦小宝125#2CBA370.6912.578.19黑底过
小龙女348#BA2C480.5255.933.54白底过
乔峰122#2CBA300.6902.578.17黑底过
段誉157#2CBA830.7032.488.46黑底过
虚竹233#2C3CBA0.4348.532.46白底过
张无忌95#67BA2C0.7092.438.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 面板自查。关掉网络也能正常使用。

相关工具