PHP 中的 WCAG 对比度验证:构建无障碍颜色工具
简介
颜色对比度是网页上最常见的无障碍问题之一。当用户可以为其个人资料、主题或内容选择自定义颜色时,你需要验证他们的选择是否保持可读性。本文将展示如何实现两个 PHP 工具函数来解决这个问题:一个用于快速亮度检查,另一个用于完整的 WCAG 合规性验证。
理解 WCAG 对比度要求
Web 内容无障碍指南(WCAG)定义了文本的最小对比度比率:
| 标准 | 普通文本 | 大文本 |
|---|---|---|
| WCAG AA | 4.5:1 | 3:1 |
| WCAG AAA | 7:1 | 4.5:1 |
大文本定义为 18pt(24px)或 14pt(18.66px)加粗。
TIP
虽然 4.5:1 符合合规要求,但这只是最低标准,而不是最高标准。许多用户仍然难以阅读最低对比度的内容。在可能的情况下,尽量使用更高的对比度。
检查颜色是浅色还是深色
对于简单的用例——比如决定在彩色背景上使用白色还是黑色文字——你可以使用基于 W3C 公式的快速亮度检查:
public static function isLightColor(string $hex): bool
{
// 如果存在则移除 #
$hex = ltrim($hex, '#');
// 将 3 位 hex 转换为 6 位
if (strlen($hex) === 3) {
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
}
// 将 hex 转换为 RGB
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
// 使用 W3C 公式计算亮度
$luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;
// 如果颜色是浅色则返回 true
return $luminance > 0.5;
}公式对绿色的权重最高(0.587),因为人眼对绿光最为敏感。
使用示例
$backgroundColor = '#3498db';
if (isLightColor($backgroundColor)) {
$textColor = '#000000'; // 在浅色背景上使用黑色文字
} else {
$textColor = '#ffffff'; // 在深色背景上使用白色文字
}完整的 WCAG 对比度验证
要正确符合无障碍要求,你需要完整的 WCAG 相对亮度计算。此函数验证颜色与白色背景是否具有足够的对比度:
/**
* 验证 hex 颜色与白色背景是否具有足够的对比度
*
* @param string $hexColor 要验证的 hex 颜色(带或不带 # 前缀)
* @param float $minContrastRatio 最小对比度比率(WCAG AA 为 4.5)
* @return bool 如果颜色具有足够的对比度则返回 True
*/
public static function hasGoodContrastWithWhite(
string $hexColor,
float $minContrastRatio = 4.5
): bool {
// 将 hex 转换为 RGB
$hex = ltrim($hexColor, '#');
// 处理 3 位 hex
if (strlen($hex) === 3) {
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
}
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
// 计算相对亮度(根据 WCAG)
$r = $r / 255;
$g = $g / 255;
$b = $b / 255;
// 线性化 sRGB 值
$r = $r <= 0.03928 ? $r / 12.92 : pow(($r + 0.055) / 1.055, 2.4);
$g = $g <= 0.03928 ? $g / 12.92 : pow(($g + 0.055) / 1.055, 2.4);
$b = $b <= 0.03928 ? $b / 12.92 : pow(($b + 0.055) / 1.055, 2.4);
// 使用 WCAG 系数计算亮度
$luminance = 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
// 计算与白色的对比度比率(亮度 = 1)
$contrastRatio = ($luminance + 0.05) / (1 + 0.05);
// WCAG AA 要求普通文本至少 4.5:1
return (1 / $contrastRatio) >= $minContrastRatio;
}重要
两个亮度公式看起来相似,但用途不同:
- W3C 公式(0.299, 0.587, 0.114):快速感知亮度检查
- WCAG 公式(0.2126, 0.7152, 0.0722):带 sRGB 线性化的精确无障碍合规性
理解 sRGB 线性化
WCAG 计算包含一个简单公式省略的关键步骤:sRGB 线性化。计算机显示器不会线性显示颜色——它们会应用伽马校正。0.03928 的阈值和转换公式将显示值转换为实际光强度:
// 对于低值(深色)
$linearValue = $srgbValue / 12.92;
// 对于较高值
$linearValue = pow(($srgbValue + 0.055) / 1.055, 2.4);这种线性化就是为什么 #777777 通过 WCAG AA 而 #787878 可能失败的原因,尽管它们在人眼看来几乎相同。
实际使用示例
验证用户选择的颜色
public function updateUserTheme(Request $request): Response
{
$primaryColor = $request->input('primary_color');
if (!hasGoodContrastWithWhite($primaryColor)) {
return response()->json([
'error' => '此颜色的文字对比度不足。请尝试更深的色调。'
], 422);
}
// 保存已验证的颜色
$user->update(['primary_color' => $primaryColor]);
return response()->json(['success' => true]);
}支持不同的 WCAG 级别
// WCAG AA 普通文本(默认)
$passesAA = hasGoodContrastWithWhite($color);
// WCAG AA 大文本(14pt 加粗或 18pt)
$passesAALarge = hasGoodContrastWithWhite($color, 3.0);
// WCAG AAA 普通文本
$passesAAA = hasGoodContrastWithWhite($color, 7.0);
// WCAG AAA 大文本
$passesAAALarge = hasGoodContrastWithWhite($color, 4.5);快速参考:常用颜色
以下是常用颜色在白色背景上的表现:
| 颜色 | Hex | WCAG AA (4.5:1) |
|---|---|---|
| 黑色 | #000000 | 通过 |
| 深灰色 | #333333 | 通过 |
| 中灰色 | #767676 | 通过(最低) |
| 浅灰色 | #777777 | 失败 |
| 海军蓝 | #000080 | 通过 |
| 标准蓝 | #0066CC | 通过 |
| 亮绿色 | #00FF00 | 失败 |
| 橙色 | #FF6600 | 失败 |
| 黄色 | #FFFF00 | 失败 |
测试你的实现
describe('hasGoodContrastWithWhite', function () {
it('深色通过', function () {
expect(hasGoodContrastWithWhite('#000000'))->toBeTrue();
expect(hasGoodContrastWithWhite('#333333'))->toBeTrue();
expect(hasGoodContrastWithWhite('#0066CC'))->toBeTrue();
});
it('浅色失败', function () {
expect(hasGoodContrastWithWhite('#FFFFFF'))->toBeFalse();
expect(hasGoodContrastWithWhite('#EEEEEE'))->toBeFalse();
expect(hasGoodContrastWithWhite('#FFFF00'))->toBeFalse();
});
it('处理 3 位 hex 表示法', function () {
expect(hasGoodContrastWithWhite('#000'))->toBeTrue();
expect(hasGoodContrastWithWhite('#fff'))->toBeFalse();
});
it('遵循自定义对比度比率', function () {
$mediumGray = '#888888';
expect(hasGoodContrastWithWhite($mediumGray, 4.5))->toBeFalse();
expect(hasGoodContrastWithWhite($mediumGray, 3.0))->toBeTrue();
});
});结论
构建无障碍应用程序需要以编程方式验证颜色选择。isLightColor 函数提供了一种快速选择对比文字颜色的方法,而 hasGoodContrastWithWhite 确保用户选择的颜色完全符合 WCAG 标准。
请记住:无障碍合规性在许多司法管辖区是法律要求。从 2026 年 4 月起,美国州和地方政府网站必须符合 WCAG 2.1 AA 标准,欧盟和其他地区也有类似的法规。

