42
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

任意の色相に対して最低コントラストを満たす色を計算する

Last updated at Posted at 2021-05-05

この記事は、Webデザインでユーザに任意のテーマカラーを選択させるときなどを想定しています。

一般に言う「色の種類」とは、HLS色空間HSV色空間の「色相」によって決定されます。

色相は、上の画像を見ていただけると分かる通り、0-360の数値で表すことができます。

HLS色空間では、「色相、彩度、輝度」によって色が決定されるので、彩度と輝度を固定して、色相のみをユーザに選択させればいいと考えることができます。

それを実装したものが以下のGIFになります。

qiita_color_theme_01.gif

しかし、実際に見てみると、赤〜青にかけては文字が見えやすい一方で、黄〜緑では文字が見えづらいことがわかります。

これは、背景色(#fff)とのコントラストが低くなることが原因です。なぜ色によってコントラストが変化するかというと、色の相対輝度にはRGBそれぞれについて重みがあり、白とコントラストが高いのは青 > 赤 > 緑です。黄色は赤と緑の中間色なので、上記の画像で黄〜緑の文字が見えづらいことにも納得できます。

相対輝度(L)の定義

{\displaystyle L=0.2126\times R+0.7152\times G+0.0722\times B}

詳しくはWIkipedia Help:配色のコントラスト比が参考になります。

では、先ほどのように彩度と輝度を固定して色相のみを変化させるのではなく、彩度のみを固定し、指定された色相に対して一定のコントラストを満たす輝度を求めてみましょう。

qiita_color_theme_02.gif

赤〜青は最初とほとんど変わりませんが、黄〜緑が見えやすくなったのが分かります。
JavaScriptの関数は以下の通りです。(chroma-jsという色操作が簡単にできるJavaScriptのライブラリを使用しています。)

// 背景色、色相、彩度、満たしたいコントラスト比を渡すと、それを満たす色(16進数)を返す
const getChromaFromHue = (
  baseColor: string,
  hue: number,
  saturation: number,
  minContrast: number
): chroma.Color => {
  const BC = chroma(baseColor)
  let left = 0
  let right = 1
  let count = 0
  while (right - left > 0.01) {
    const middle = Math.floor(((left + right) / 2) * 100) / 100
    const color = chroma(hue, saturation, middle, 'hsl')
    if (chroma.contrast(BC, color) > minContrast) {
      left = middle
    } else {
      right = middle
    }
    if (count > 5) break
    count += 1
  }
  return chroma(hue, saturation, left, 'hsl').hex()
}

const changeThemeColor = (hue: number) => {
  setThemeColor({
    theme: getChromaFromHue('#fff', hue, 0.7, 1.7),
    themeAA: getChromaFromHue('#fff', hue, 0.5, 4.5),
    themeAAA: getChromaFromHue('#fff', hue, 0.4, 7),
    themeLight: getChromaFromHue('#fff', hue, 0.5, 1.05),
  })
}

関数内の処理としては、指定されたコントラストを満たす最高の輝度を二分探索で求めています。
(二分探索せずに求める式があれば教えてください:bow_tone1:)

ここで、コントラスト比 > 4.5を満たすものはアクセシビリティ適合レベルAAコントラスト比 > 7.0を満たすものはアクセシビリティ適合レベルAAAです。文字色のコントラストはAA以上は満たすか、テーマをAA以上に変更するオプションなどは用意するといいでしょう。

AAを満たすボタンを設置した例
qiita_color_theme_04.gif

42
33
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?