🔖

CSSの関数で背景色に合う文字色を選ぶ

2021/05/26に公開

前置き

最近のCSSは自由度が跳ね上がって割と何でもできる感じが出てきました。かつて実装するだけで阿鼻叫喚の嵐を招いたライフゲーム[1]も今や不特定多数が実装するレベルまで敷居が下がっており、完成度のインフレが止まらない夏休みの自由研究っぽさがあります。かなりあります。
さて、私は今回背景色から文字色を決める機能がCSSに無いか探しました。実装しようとしているものはカラーテーマのカスタムを機能として考えていますが、カラーテーマがカスタムできるからにはそこに文字色も合わせる必要があるからです。
もし文字色を合わせることが無ければ、例えば黒地に黒といった人生の意味について考えさせられる文様、あるいは白地に白といった余りの眩しさに眼球を焼かれること間違いなしのインシデントが発生してしまいます。発生しまくります。これを回避するためにはただ一つ、CSSのその豊富な関数で背景色に合う文字色を選ぶ機能を実装するしかないのです。[2]

方針

https://zenn.dev/mryhryki/articles/2020-11-12-hatena-background-color
基本的にこの記事の前半部分をパクってそのままCSSで実装する方向で行きます。リンクを開けばわかる通りこの記事では後半部分でより精密かつアクセシビリティに配慮されたアルゴリズムが記載されているんですが、単純に面倒なのとそもそも実験中関数を使わないと実現できない気配がするため前半です。

仕様

  • 背景色は、body要素内にてそのRGB値を--back_r,--back_g,--back_bの3変数によって入力されるものとする[3]
    • 入力例:
body{
    --back_r:2;
    --back_g:2;
    --back_b:2;
}
  • 文字色は、#000000または#FFFFFFの2種類から選択するものとする
  • 文字色算出を行う要素には.getcharcolorのクラスが付与されるものとする

実装

輝度(Y)を算出する

元記事で言う

const brightness = Math.floor((parseInt(red, 16) * 0.299) + (parseInt(green, 16) * 0.587) + (parseInt(blue, 16) * 0.114))

の部分です。

基本的にcalc()関数をいじくればすぐです。

.getcharcolor{
    --y:calc(calc(var(--back_r) * 0.299) + calc(var(--back_g) * 0.587) + calc(var(--back_b) * 0.114));
}

floorは割と普通に実装が辛かったので割愛します(カス)

色を算出する

問題はこっちです。
元記事で言う

const color = brightness >= 140 ? '000000' : 'FFFFFF'

の部分です。
CSSにはmax()関数やmin()関数があるので、これを駆使して条件分岐していく形になります。具体的に言うと、

  1. min(140,y)で「140未満」と「それ以外[4]」を選別する
    • 「140未満」の場合そのまま、「それ以外」の場合140になる
  2. ここに-1を掛け、140を足す
    • これによって「140未満」の場合0超に、「それ以外」の場合0になる
  3. 適当に10000くらいのデカい数字を掛ける
  4. min(255,(3で出た数))で「140未満」の場合255に、「それ以外」の場合0になる
  5. rgb((4で出た数),(4で出た数),(4で出た数))で文字色が求められる

これを実装すると、こうなります。

.getcharcolor{
    --y:calc(calc(var(--back_r) * 0.299) + calc(var(--back_g) * 0.587) + calc(var(--back_b) * 0.114));
    --c:min(255,calc(calc(min(140,var(--y)) * -1 + 140) * 10000));
    color:rgb(var(--c), var(--c), var(--c));

はい。[5]

確かめてみる

ひとまずスタイルは完成したわけですが、何事も試してみなければ成功とは言えません。実際にテストするその瞬間まで、人生の意味や焼かれる眼球は可能性として残り続けるのですから。

そういうわけで、確かめるためのページを作りました。
使ったのは、もちろんJavaScriptです!!!!!!!!!!!!!!!!!!!!

良い感じですね!!!!!!!!

まとめ

JavaScriptはすごい

脚注
  1. ルール110セル・オートマトンの方が多いか? ↩︎

  2. JavaScriptの事は考えないでください ↩︎

  3. JavaScriptの事は考えないでください ↩︎

  4. 言い換えれば、「140以上」 ↩︎

  5. JavaScriptの事は考えないでください ↩︎

Discussion