提高浏览器的可访问性 - 对比度计算
为了确保网站和应用程序能够被更广泛的用户群体使用,关注和提高可访问性是至关重要的。而在可访问性中,对比度是一个非常关键的因素。对比度指的是前景色(文本或图标)与背景色之间的明暗差异程度。在浏览器中,我们可以检查和评估前景和背景色的对比度,以确保内容易于阅读和辨别。
在浏览器中使用开发者工具选择元素,可以看到类似下图的 popup 框。其中 Contrast 字段可以检查选中文字的对比度信息。图中前背景色的对比度达到 6.33,符合标准,因此可以观察到一个绿色的对勾符号。
虽然较低的对比度会显得用色比较“高级”,然而对于有视觉障碍的用户、老年人或者在光线较暗的情况下使用设备的用户来说,更安全的对比度可以帮助用户更轻松地阅读内容,为所有用户提供更好的用户体验。因此为了设计出更加专业的 UI,我们最好能够遵循可访问性标准,设计较高对比度的界面。
可访问性标准
在可访问性方面,有两个主要的对比度标准:AA 和 AAA。这些标准由 Web 内容可访问性指南(WCAG)制定,用于确保内容的可读性和可访问性。
- AA 级别要求:AA 级别要求最低的对比度水平,适用于大多数普通文本和图像。根据 WCAG 2.0 AA 级别,正常文本的对比度应至少为 4.5:1,对于大文本来说,由于它们本来就比较好辨认,对对比度的要求较低,至少为 3:1。
- AAA 级别要求:AAA 级别要求更高的对比度水平,适用于需要更好可读性的特殊情况,如长时间阅读、小字号文本等。根据 WCAG 2.0 AAA 级别,正常文本的对比度应至少为 7:1,而大文本的对比度应至少为 4.5:1。
基础的对比度检测
我们可以基于两个颜色的亮度差异来计算对比度。而直接比较两个颜色哪个亮对人来说其实比较困难。因此我们常将 RGB 颜色先转换为灰度值。我们可以使用如下的公式转换 RGB 颜色至灰度值:
这个公式中有一些意味不明的魔法值权重。这些权重是根据人眼对不同颜色的感知差异进行了实验和统计分析得出的。它其实基于一种称为 Luma 或 ITU-R BT.709 的标准。相对于绿色通道,人眼对红色通道更不敏感,对蓝色通道最不敏感,因此相应地给予了较低的权重。
然后我们根据灰度值,通过下列公式来计算对比度:
其中, 表示对比度, 表示较亮的颜色的亮度值, 表示较暗的颜色的亮度值。
然而仅靠上述的公式算出的对比度并不正确,这是因为处理时的色彩空间不同。
色彩空间
最常见的颜色表示法——RGB,通过组合红色(R)、绿色(G)和蓝色(B)的不同强度来创建所需的颜色。RGB 值通常使用 0-255 的整数表示,每个通道的值表示对应颜色分量的强度。
CSS 中默认使用的是 sRGB 色彩空间。它广泛应用于计算机和互联网上的图像和显示设备。默认情况下,CSS 中的 RGB 值处于 sRGB 色彩空间中。这种色彩空间是非线性的,并不适合进行色彩相关的计算操作。
在我们的场景下,更适合使用线性 RGB 色彩空间。这是一种线性表示颜色强度的色彩空间,其中每个通道的颜色值与物理光的亮度成正比。这种线性关系使得颜色的计算更加直观和精确。
通过将 sRGB 空间的颜色转换为线性 RGB 空间,可以消除颜色值在 sRGB 中的非线性响应。这样,在进行颜色操作时,可以更准确地处理光的物理性质,使得颜色混合、亮度调整和比较等操作更加精确和可预测。
具体操作如下:
- 首先,我们将颜色通道的值除以 255,将其归一化到 0 到 1 的范围内,以便在接下来的计算中使用。
- 接着,我们使用 sRGB 校准曲线来计算相对亮度。如果归一化后的值小于等于 0.03928,我们将其除以 12.92,以进行线性转换。
- 如果归一化后的值大于 0.03928,我们将其加上 0.055,然后将结果除以 1.055。接着,我们将结果进行 2.4 次方运算,以进行非线性转换。
最终,可以下面的 Typescript 代码,实现色彩空间转换和对比度计算的功能:
interface RGBColor {
r: number
g: number
b: number
}
function calculateContrast(rgb1: RGBColor, rgb2: RGBColor): number {
// 计算颜色的相对亮度
const l1 = calculateRelativeLuminance(rgb1)
const l2 = calculateRelativeLuminance(rgb2)
// 计算对比度
const contrast = (l1 + 0.05) / (l2 + 0.05)
return contrast
}
function calculateRelativeLuminance(rgb: RGBColor): number {
const { r, g, b } = rgb
const sRGB = [r / 255, g / 255, b / 255]
const [rL,gL,bL] = sRGB.map((c) => {
if (c <= 0.03928) {
return c / 12.92
}
else {
return ((c + 0.055) / 1.055) ** 2.4
}
})
const l = 0.2126 * rL + 0.7152 * gL + 0.0722 * bL
return l
}
// 示例用法
const color1: RGBColor = { r: 255, g: 0, b: 0 }
const color2: RGBColor = { r: 0, g: 255, b: 0 }
const contrast = calculateContrast(color1, color2)
console.log(`Contrast: ${contrast}`)
最后,我强烈推荐一个名为 "Color Contrast Checker - Coolors" 的网页应用。这个应用不仅可以检查颜色的对比度是否符合无障碍标准,还可以自动调整颜色以满足安全对比度的需求。