0%

WCAG標準-色彩對比度

1. 色彩對比度

腦袋需要簡單記一下的基本比例

AA 級對比度

文本和文本圖像的視覺呈現至少需有 4.5:1 的對比度。

大文本(加粗的 14pt/普通的 18pt 及以上)和大文本圖像的對比度至少需為 3:1

AAA 級對比度

文本和文本圖像的視覺呈現至少需有 7:1 的對比度。

大文本(加粗的 14pt/普通的 18pt 及以上)和大文本圖像的對比度至少需為 4.5:1

參考 Material Design 和 iOS 人機交互規範,基本都是以滿足 AA 級標準為主。在特殊情況下才要求滿足 AAA 級標準。

2. 顏色對比度公式

稍微了解一下對比度的公式,簡單來說就是RGB去乘上係數再做一些轉換…頭昏請跳過。

顏色對比度的計算公式源自 WCAG(Web Content Accessibility Guidelines,網頁內容無障礙指引),透過比較兩個顏色的亮度來得到對比比率,以衡量文字與背景之間的清晰度。

對比度比率計算公式:
$$
\begin{align*}
\text{Contrast Ratio} = \frac{L_1 + 0.05}{L_2 + 0.05}
\end{align*}
$$

$$
\begin{align*}
其中 L_1 是兩個顏色中亮度較高的那個顏色的亮度值。
L_2 是 亮度較低的那個顏色的亮度值。
\end{align*}
$$

亮度L的計算公式:
$$
\begin{align*}
L = 0.2126 \times R + 0.7152 \times G + 0.0722 \times B
\end{align*}
$$
在此公式中,( R )、( G )、( B ) 分別為顏色的紅、綠、藍通道值,它們需要先經過線性轉換。若原始的 RGB 值在 0–255 範圍內,首先應進行歸一化(除以 255)並進行線性化處理:

RGB 值的線性化處理

對於每個顏色通道的值 v,按以下方式轉換:

$$
\begin{align*}
若 v \leq 0.03928 :則 v = \frac{v}{12.92}
\end{align*}
$$

$$
\begin{align*}
若v > 0.03928 :則 v = \left(\frac{v + 0.055}{1.055}\right)^{2.4}
\end{align*}
$$

計算步驟示例

  1. 取得顏色的 RGB 值(例如 #FFFFFF 的 RGB 值為 255, 255, 255)。

  2. 進行 RGB 值的歸一化(例如 255 變成 1.0,0 變成 0.0)。

  3. 線性化每個通道,然後代入亮度公式
    $$
    \begin{align*}
    L = 0.2126 \times R + 0.7152 \times G + 0.0722 \times B
    \end{align*}
    $$

  4. 將亮度值代入對比度公式計算比率,並確保亮度較大的顏色作為 ( L1 ),亮度較小的顏色作為 ( L2 )。

對比比率的解釋

  • 1:1 表示完全無對比(如兩個相同的顏色)。
  • 21:1 表示最高對比度(黑與白)。

符合 WCAG 標準的常見對比度要求為:

  • 正文字體的對比度需達到 4.5:1
  • 大字體(18pt 或更大;14pt 粗體或更大)需達到 3:1

3. JS程式實踐

好奇程式會怎麼寫,於是…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 將 HEX 顏色轉換為 RGB
function hexToRgb(hex) {
// 去掉開頭的 `#` 字元
hex = hex.replace("#", "");

// 解析 HEX,轉換為 RGB
let bigint = parseInt(hex, 16);
let r = (bigint >> 16) & 255;
let g = (bigint >> 8) & 255;
let b = bigint & 255;

return [r, g, b];
}

// 計算 RGB 顏色的相對亮度
function getRelativeLuminance(r, g, b) {
// 歸一化 RGB 值,範圍為 0 到 1
r /= 255;
g /= 255;
b /= 255;

// RGB 的線性化處理
r = (r <= 0.03928) ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
g = (g <= 0.03928) ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
b = (b <= 0.03928) ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);

// 計算相對亮度
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

// 計算兩個顏色的對比度
function getContrastRatio(hexColor1, hexColor2) {
// 轉換 HEX 顏色為 RGB
const [r1, g1, b1] = hexToRgb(hexColor1);
const [r2, g2, b2] = hexToRgb(hexColor2);

// 計算兩個顏色的相對亮度
const L1 = getRelativeLuminance(r1, g1, b1);
const L2 = getRelativeLuminance(r2, g2, b2);

// 計算對比度比率
const contrastRatio = (L1 + 0.05) / (L2 + 0.05);

// 回傳對比度,確保 L1 是亮度較高的顏色
return L1 > L2 ? contrastRatio : 1 / contrastRatio;
}

// 範例測試
const color1 = "#FFFFFF"; // 白色
const color2 = "#000000"; // 黑色
console.log("對比度比率:", getContrastRatio(color1, color2)); // 期望輸出 21:1

4. 網站實際應用

在螢光筆的顏色選擇上考量顏色對比度問題,特別轉換計算結果,確保有符合AA要求。

image-20241112095035413

5. 參考連結