“好看”是口味问题;“看得清”却可以测量。 灰得发淡的文字在好显示器上没问题, 到了白天的手机屏上就消失了 —— 靠眼睛挑颜色,迟早会出这种事。
python3 addons/gohud/tools/check_contrast.py
| 对象 | 要求 |
|---|---|
| 正文文字 | 4.5 : 1 |
| 大号文字(24px 及以上) | 3 : 1 |
| 强调色的边框和图标 | 3 : 1 |
| 装饰性边框 | 2 : 1 —— WCAG 的 3:1 规则不适用于纯装饰 |
| 相邻表面 | 1.12 : 1 —— 足以让卡片从背景中区分出来 |
同色相文字压在同色相底色上
这个坑在本项目里出现过三次 —— 按下状态的按钮(强调色面板配强调色文字)、 危险按钮,以及标签片。它在色卡上看着挺好,一测就崩, 因为两者色相相同,明度上也就没有差别。
所以文字颜色不是手工挑的。主题生成器和 GoSkin 各自只推明度 ——
而且只推明度 —— 直到它在文字真正落脚的那块面板上达标为止。色相和饱和度保持不变,
因此调色板保留了自己的性格,改动它也不会丢掉对比度。
当文字读的颜色和当色块涂的颜色,要求正好相反
在浅色主题上,警告色当文字用时必须压暗才读得清(#96500A)。
而状态条的填充要是继承了这个值,经验条就变成褐色了。光靠颜色解决不了:
黄色本身就亮,所以哪怕底槽完全不加灰也能过 3:1,而把底槽压暗只会让情况更糟(1.52 → 1.06)。
于是把两者分开。颜色保持鲜艳 —— 调色板里带有仅用于填充的颜色,例如
warning_vivid。对比度交给边缘来扛 —— 只要某个填充在自己的底槽上达不到 3:1,
GoSkin 就给它画一圈 1dp 的描边,这样“到底满了多少”依然看得清。
MY_LIGHT = dict(
warning=hexc("9A5407"), # 当文字读
warning_vivid=hexc("F2A007"), # 涂在状态条上
)
*_vivid 时,若填充色算出来偏暗,生成器就会打印
the bar looks drab — add warning_vivid to the palette(生成器实际输出的原文,意为“状态条发暗 —— 请在调色板里加上 warning_vivid”)。
以前会悄悄劣化的地方,现在会开口说话。
浮动面板不可能知道自己背后是什么
HUD 是画在游戏画面之上的 —— 背后可能是雪原,也可能是洞窟。如果它的面板半透明,
背后的东西就会透上来,改变面板的颜色,文字对比度也跟着被拖下去。
在 82% 不透明度下,深色主题的弱化文字在明亮背景上掉到了 3.74:1 —— 低于下限。
所以半透明面板一律以纯白和纯黑作为背景来测量;游戏场景能给出的最坏情况也就是这两种了。 随包主题的 HUD 面板不透明到足以达标(92%),同时仍保留那种玻璃质感。
同理,图标颜色也不写死。快捷槽里的图形原本被硬编码成白色,在浅色主题上量出
1.11:1 —— 现在它会跟随自己所在的面板,和文字的做法完全一样。
check_contrast.py 读的是主题文件;
皮肤在运行时混出来的颜色(标签片、快捷槽)则由测试套件在 Godot 内部的
skin contrast 一节来测量。