網頁設計中,文字是最常用的元素之一,文字易讀性非常重要,我們都希望頁面更加清晰易讀,而顏色在文字易讀性中起到了至關重要的作用。
文字和背景顏色有一個“對比度”,瞭解並能正確調整這個對比度,將會讓你的頁面更加清晰易讀,進而提高閱讀效率和閱讀體驗。
問題的由來:拯救你慘不忍睹的頁面設計
在缺乏專業設計的頁面中,我們經常見到下面這樣的畫面:
這是公司的某內部系統:
公司某內部工具:
有沒有覺得上面的文字特別刺眼,難以識別?
標準
上面的兩個案例,本質上都是文字色與背景色的“對比度”不足導致的,足夠的色彩“對比度”可讓文字和圖片更易於閱讀和理解。
“對比度”是指螢幕上兩種相鄰顏色之間的亮度或發出光線的強度的差異計算值。這個比值的範圍在 1 到 21 之間(通常寫為 1:1 到 21:1);該值越大,則對比度越高。
實際上,W3C 的 Web 無障礙推進組織制定了 Web 內容無障礙指南(WCAG),這個指南涉及了一些建議,這些建議可使 Web 內容更容易訪問。遵循這些原則,能夠讓內容更易為廣大殘障人士所接受,包括失明和低視力、失聰和重聽、學習障礙、認知障礙、行動不便、言語殘疾、光過敏患者和這些病症的複合患者。遵循這些原則也可讓普通使用者更容易訪問 Web 內容。
簡單總結一下這個標準:
對比度等級 | 普通文字 | 大型文字 |
---|---|---|
AA | 4.5:1 | 3:1 |
AAA | 7:1 | 4.5:1 |
對比度等級:
- AA 級: 符合要求的最小對比度
- AAA 級: 增強版的對比度,文字更清晰
字型大小的分界線:
- 普通文字: 小於 18 磅的常規字型或 14 磅的加粗字型
- 大型文字: 於 18 磅的常規字型或 14 磅的加粗字型
那麼如何實現符合 WCAG 規範的對比度呢?如何在專案中漸變快捷地進行調整呢?
使用工具調整對比度
有很多工具可以調整對比度,這裡列舉一些我使用過的工具:
1. 色彩對比度計算器
一個線上的,計算任意兩種有效 CSS 顏色之間對比度的工具。
兩側分別為文字顏色與背景色,中間一個醒目的圓盤,顯示二者的對比度,滑鼠移動到這個圓盤上可以檢視該對比度符合 AA/AAA 對比度標準。
2. Chrome 瀏覽器控制檯
對於開發的同學來說,這種方式也很快捷方便。新版的 Chrome 瀏覽器增強了 CSS 的調色功能:
開啟控制檯,選中一個 文字元素 然後在 Styles 中找到 color 屬性,點選 顏色值,可以看到一個調色盤。
然後點選調色盤的 Contrast radio 選項,展開對比度計算工具,可以看到上方的調色盤出現一條白線,這條白線就是符合 AA 級對比度標準的臨界值。調色盤中的圓圈就是當前選中的色值,拖動這個色值即可調整文字顏色,這時下方的對比度計算工具進行了實時計算:
3. 使用 JS 進行精準計算
通過構建工具即可在構建時進行對比度的驗證,從而保證 UI 中的文字易讀性符合標準。
有一些開源的 JS 庫可以進行對比度的計算,這裡我找到了一個很好用的庫: TinyColor, 通過 readability 函式計算兩個顏色的對比度:
tinycolor.readability("#000", "#000"); // 1
tinycolor.readability("#000", "#111"); // 1.1121078324840545
tinycolor.readability("#000", "#fff"); // 21
複製程式碼
通過 isReadable 函式判斷是否符合 AA/AAA 級對比度標準:
tinycolor.isReadable("#000", "#111", {}); // false
tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AA",size:"small"}); //false
tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AA",size:"large"}), //true
複製程式碼
通過 JS 進行對比度的計算,舉個例子,一個最常見的場景: 手機頂部狀態列中文字非常顯眼,背景色多變,但文字色的正確搭配往往被忽視,下圖是我們 APP 中某個頁面的狀態列:
可以看到狀態列的文字是黑色,而 header 中的文字顏色又是白色,一般來說狀態列的顏色設定為黑色或白色(iOS 中只能設定這兩種顏色),這時狀態列的顏色最好根據 js 來計算,人為設定黑色或白色容易搭配不當或者遺漏配置。
一些技巧
1. 文字使用帶有半透明度的黑色或白色
在彩色背景上使用灰色文字會降低對比度:
最早是在 Material Design 的設計規範中看到的這個技巧,使用透明的黑白色文字和彩色背景的時候,文字顏色會混合成相應的深色,例如上圖中的深粉色。這樣做的好處是背景顏色變化的時候文字顏色會自動混合成對應的深色,不必改變文字的顏色值。
2. 告別五彩斑斕的文字
頁面中色彩不宜過多,謹慎使用彩色文字,應該把彩色留給按鈕、連結、開關等元件,這樣做的好處是文字層次鮮明,失去控制的過多色彩會讓內容缺乏重點。
正文使用黑白色(在大段的正文中使用彩色文字不利於閱讀)
3. 使用不同半透明度的文字
按照功能的重要性,為文字制定不同半透明度的規範,從而對不同層次資訊的對比度加以區分。
使用不同半透明度的文字,用於區分標題、正文、描述文字、提示文字和icon。這樣做可以讓讀者閱讀起來有一定的優先順序關係,可以讓資訊層次鮮明,有助於使用者理解關鍵資訊,減少閱讀時候的疲勞感。
4. 多種色彩的背景上使用文字
如果背景的色彩比較複雜(如漸變色、圖案等),則可以根據平均值來作為背景色計算對比度。
如果背景色的色彩差異較大,則應在文字和背景之間新增遮罩。
5. 使用 JS 進行對比度的計算
即上文提到的使用 TinyColor 工具進行精確計算,在構建工具中驗證。
6. 根據實際場景調整對比度
雖然 WCAG 提出了 AA/AAA 級對比度標準,但是實際使用時應從使用者角度出發,根據實際場景確定是否需要更強烈的對比度,舉幾個例子:
- 裝置質量:螢幕質量是否比較差、投影儀是否老化,顯示效果不好的時候應提高對比度
- 分散注意:使用者在跑步、乘車、嘈雜環境這樣的不穩定場景中使用,分散在介面上的注意力會大打折扣,這時應提高對比度
- 使用者視覺能力:近視、散光甚至色盲、色弱的比例
- 其他影響:是否有其他光源影響顯示
演算法探究與優化
Material Design 根據對比度判斷使用黑色/白色的原始碼
這段程式碼用 sass 實現了若干函式,其中:
** 1. @function mdc-theme-contrast-tone ** 傳入一個顏色值,返回該顏色背景上應該使用的顏色為 light / dark 顏色
** 2. @function mdc-theme-tone ** 傳入一個顏色值,返回該顏色為 light / dark 顏色,核心程式碼:
// 傳入的顏色值為 $color
$lightContrast: mdc-theme-contrast($color, white); // 計算傳入顏色和白色的對比度
$darkContrast: mdc-theme-contrast($color, rgba(black, .87)); // 計算傳入顏色和黑色的對比度
$minimumContrast: 3.1; // 設定最小對比度
@if ($lightContrast < $minimumContrast) and ($darkContrast > $lightContrast) {
// 傳入的顏色值和白色的對比度小於最小對比度 並且 和黑色的對比度更高
@return "light"; // 我們認為傳入的顏色是淺色
} @else {
// 我們認為傳入的顏色是深色
@return "dark";
}
複製程式碼
3.? 上面的程式碼中用到了計算對比度的函式 mdc-theme-contrast 也在這段程式碼中,對比度是這樣計算的:
// 計算顏色的相對亮度(relative luminance)
@function mdc-theme-luminance($color) {
$red: nth($mdc-theme-linear-channel-values, red($color) + 1);
$green: nth($mdc-theme-linear-channel-values, green($color) + 1);
$blue: nth($mdc-theme-linear-channel-values, blue($color) + 1);
@return .2126 * $red + .7152 * $green + .0722 * $blue;
}
// 計算兩個顏色的對比度(contrast ratio)
@function mdc-theme-contrast($back, $front) {
$backLum: mdc-theme-luminance($back) + .05;
$foreLum: mdc-theme-luminance($front) + .05;
@return max($backLum, $foreLum) / min($backLum, $foreLum);
}
複製程式碼
這裡用到了一個對比度計算公式: www.w3.org/TR/WCAG20-T…
可以看到一些有趣的引數:
@return .2126 * $red + .7152 * $green + .0722 * $blue;
複製程式碼
相同的色值,綠色要顯得亮一些,相反藍色要顯得暗一些。
優化:支援半透明度顏色混合
Material Design 在計算傳入顏色和黑色的對比度時,傳入的是一個帶有半透明度的色值,實際上在執行時會按照純黑色(不帶有半透明度)進行解析。
$darkContrast: mdc-theme-contrast($color, rgba(black, .87)); // 計算傳入顏色和黑色的對比度
複製程式碼
我理解的 rgba(black, .87) 指的是 Material Design 規定的正文字型顏色(深色),因此這裡按照半透明色進行解析會更好一些,這樣我們判斷顏色是深色還是淺色時的依據就是頁面上最深的文字顏色 (#000 87%) 和最淺的背景顏色 (#fff 100%) 了。
用 js 來實現這個混合的過程 (依賴 tinycolor):
// Alpha 合成 支援前景色半透明
function mixColor(front, back) {
var rgbFront = tinycolor(front).toRgb();
var rgbBack = tinycolor(back).toRgb();
var alphaFront = rgbFront.a;
var mixR = alphaFront * rgbFront.r + (1 - alphaFront) * rgbBack.r;
var mixG = alphaFront * rgbFront.g + (1 - alphaFront) * rgbBack.g;
var mixB = alphaFront * rgbFront.b + (1 - alphaFront) * rgbBack.b;
var res = tinycolor({ r: mixR, g: mixG, b: mixB }).toHexString();
return res;
}
複製程式碼
Alpha 合成演算法來自: 維基百科 - Alpha 合成
優化:支援調節最小對比度
Material Design 中最小對比度是寫死的 3.1,不知道為什麼沒有設定為 AA/AAA 級對比度標準,這裡可以傳入引數來指定最小對比度:
function contrast(color, contrast) {
if (color === 'light' || color === 'dark') return color;
var minimumContrast = contrast || 3.5;
var lightContrast = getContrast(color, '#fff');
var darkContrast = getContrast(color, '#000');
if (lightContrast < minimumContrast && darkContrast > lightContrast) {
return 'light';
} else {
return 'dark';
}
}
複製程式碼
用 js 實現
上文提到的 Material Design 的原始碼包含的幾個函式,在 TinyColor 這個工具裡都有實現。
我按照 Material Design 的實現思路,用 js 實現了一遍,增加了上文提到的兩個優化點 (支援半透明度顏色混合 / 支援調節最小對比度): 原始碼地址