k8o

色のコントラスト比は重要だけどどうやって求めるんだっけ?

公開: 2024年2月12日(月)
更新: 2024年9月28日(土)
444 views

WCAG 2.1では背景色とテキスト色のコントラスト比についての達成基準が定められています。コントラスト比とは何でしょうか?コントラスト比の計算はツールを用いることが多いので、その計算方法を理解せずに検査している方は少なくないです。この記事ではコントラスト比の計算方法を理解して、そこから読み取れる重要な情報を紐解きます。

color contrasta11yWCAGW3C

はじめに

背景色とテキスト色のコントラスト比はWCAG 2.1においてAA基準AAA基準の2つの達成基準によって定められています。 AA基準における大文字のテキストの最小コントラスト比は4.5:1、小文字のテキストの最小コントラスト比は3:1です。AAA基準においては、大文字のテキストの最小コントラスト比は7:1、小文字のテキストの最小コントラスト比は4.5:1です。 大文字のテキストは18pt(24px)以上、太字の場合は14pt(18.66px)以上です。小文字のテキストは14pt(18.66px)以上、太字の場合は12pt(16px)以上です。 これらの基準はコントラストに対する支援技術を用いない中程度の弱視の人がテキストを読めることを目的として設けられています。

この基準はWebAIMのチェッカーや、storybookのa11yに関するアドオンのようなツールを用いて確認できます。 ツールを使って簡単に求められるので、その背後にある計算方法を理解せずに使うこともできます。しかし、計算方法を理解した上で活用することはデザインの質を向上させるうえで有益です。私も以前はツールに頼りっぱなしでしたが、最近、色のコントラスト比を計算する方法を知り、その重要性を理解しました。この記事では色のコントラスト比の計算方法について紹介します。

計算式

コントラスト比はお互いの色の相対輝度を用いて表されます(輝度(きど、英: luminance)とは、広がりを持つ光源からある方向へ射出される光(可視光)の面積あたりの明るさを表す物理量である。^1)。相対輝度をLLで表した場合、コントラスト比CCはその比率を取るように計算されます。

C=(L1+0.05)(L2+0.05)C = \frac{(L_1 + 0.05)}{(L_2 + 0.05)}

L1L_1L2L_2よりも相対的に明るい色となるようにします。輝度の定義より明るい色は暗い色よりも輝度が大きいので、与式は11以上になります。 さらに定数として分母と分子に、周囲光の影響として0.050.05を加えています。これによって与式の分子と分母が00になることを防いでくれています。 これから計算方法を紹介しますが、相対輝度LL010 \sim 1の値をとります。さらに、計算結果は1以上の値になることを踏まえるとコントラスト比は1211\sim 21の値をとります。

相対輝度は色空間内の任意の点の相対的な明るさです。最小値が#00000000、最大値が#ffffff11となるように正規化されます。 色の表現法は様々ありますが、計算では(R,G,B)(R,G,B)で赤・緑・青のそれぞれ010\sim1の数値で表したものを使います。#4080c0であればそれぞれを16進数で表した(64,128,192)(64,128,192)256256で割った(0.25,0.5,0.75)(0.25,0.5,0.75)を使います。 そしてそれぞれの成分を以下のルールに基づいて変形します。

F(x)={x12.92x0.04045(x+0.0551.055)2.4x0.04045 F(x) = \begin{cases} \frac{x}{12.92} \quad x \leqq 0.04045 \\ (\frac{x + 0.055}{1.055})^{2.4} \quad x \ge 0.04045 \\ \end{cases}

F(x)は単調増加関数で、xxの最小値は0、最大値は1です。そのため、F(x)F(x)の最小値もF(0)F(0)、最大値はF(1)F(1)となり010\sim1の値を取るようになります。

これらの計算は人間の視覚が色の明るさを非線形に捉える特性を補正するために行います。

輝度に対しての物理的な明るさと人間が感じる明るさを図示したグラフ

^2

明るい色は暗い色と同じ変化でも輝度を大きく感じることが見て取れます。与式ではそれが2.42.4乗によって表されています(下図はy=x2.4y = x^{2.4}をプロットしたものです。軸が逆なことに注意してください)。

y=xの2.4乗をxの範囲が0から1で表記したグラフ

また、0.040450.04045以下ではその寄与が過度になってしまうので単純に12.9212.92で割るだけの式になっています。

計算した結果を赤・緑・青それぞれの見え方に合わせて重みをつけて足し合わせると相対輝度が求められます。

L=0.2126×R+0.7152×G+0.0722×B L = 0.2126 \times R + 0.7152 \times G + 0.0722 \times B

重みの合計は1です。LLも同じく010\sim1の値を取るようになっています。 重みの付け方も人間の視覚で捉えやすい色を基準に設けています。人間は緑色に対する感受性が最も高く、次に赤色、最後に青色の順で感じるので緑が最も相対輝度に寄与して、青が最も寄与しないような重みづけになっています。

コード

計算式を学んだのそれをコードに落とし込んでいきましょう。 まずは補正を行う関数を作っていきます。

const applyCorrection = (color: number): number => {
  if (color <= 0.04045) {
    return color / 12.92;
  }
 
  return Math.pow((color + 0.055) / 1.055, 2.4);
};

colorには0 10~1の範囲外の数値を渡せますが、この記事ではそのような数値を考えないものとして記述します。

次に相対輝度を求める関数です。

type RGB = [number, number, number];
 
const computeRelativeLuminance = (correctionRgb: RGB): number => {
  const [r, g, b] = correctionRgb;
  return (
    0.2126 * applyCorrection(r) +
    0.7152 * applyCorrection(g) +
    0.0722 * applyCorrection(b)
  );
};

number型の3つ要素を持つタプル型をRGBという名前で作りました。

最後にコントラスト比を求める関数です。

const computeContrastRatio = (rgb1: RGB, rgb2: RGB): number => {
  const l1 = computeRelativeLuminance(rgb1);
  const l2 = computeRelativeLuminance(rgb2);
  return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
};

相対輝度の計算が終わるまでどちらが明るいか分からないので、計算後に大きい方が分子に、小さい方が分母になるように調整しています。

さいごに

コントラスト比の計算方法について紹介しました。人間の視覚で感じやすい色についての情報や、コントラスト比を高めるためには緑の要素を強めると青の要素を強めるのに比べて10倍の効果があるなどツールで調整するだけでは分からなかったことが読み取れるようになりました。 今後もツールを使って結果を鵜呑みにするだけではなく、結果がどのように導かれるかを理解していきたいです。