JavaScriptでこういうことがしたい。
- ある色コード #XXXXXX がある
- その補色の #YYYYYY を求めたい
こういう補色をコード的に求めたいです。
簡単だけど補色の定義を知らないと悩みました。
そういった基本的な色の知識も含め、
JavaScriptで補色を求める方法を紹介します。
このページの目次
補色の厳密な定義とは?色反転ではない
そもそも補色には2種類あります。
- 物理補色
- 心理補色
ここでの補色は物理補色のことです。
▼ 物理補色とは何か?詳しい解説
補色 カラーの各構成要素を、選択したカラーの最大の RGB 値と最小の RGB 値の合計を元にして、新しい値に変更します。現在のカラーの RGB 値のうち最大と最小の値が合計され、その値から各構成要素の値を引いて、新しい RGB 値が生成されます。
例えば、RGB 値がレッド 102、グリーン 153、ブルー 51 であるカラーを選択したとします。この場合、まず最大値である 153 と最小値である 51 を合計して 204 という値が算出されます。この値から既存のカラーの RGB 値がそれぞれ差し引かれます。つまり、新しいレッドの値は 204 - 102(現在のレッドの値)= 102、グリーンの値は 204 - 153(現在のグリーンの値)= 51、ブルーの値は 204 - 51(現在のブルーの値)= 153 となり、新しい補色の RGB 値が生成されます。
これが物理補色の厳密な定義。
単純に色を反転させてる訳ではありません。
それさえ分かれば補色は求められます。
補色と反転色は同じではない。全く違う
さらに補色と反転色について補足。
この2つは全く別物なので注意しないといけません。
▼ 分かりやすい解説
「反転色も補色も、色相が±180°になる点では一緒」ですが、「反転色では、彩度や明度が変化」するのに対して、「補色では、彩度や明度は一定」に保たれます。反転色では「255」に対するRGB値の差ですが、補色では「最大値+最小値」に対するRGB値の差です。
この点は後々紹介するコード作成でも重要です。
補色を16進数表記から求めるロジック
通常、色は16進数表記で表されます。
▼ その補色を求める流れというのが次
- 16進数の色コードをRGB配列に変換
- RGB配列の最大値と最小値を足す
- その値からRGBの各要素を引く
- 補色のRGB配列を16進数表記に直す
言葉で書くととても分かりにくい…
よりイメージしやすい具体例を出します。
▼ 赤(#ED1A3D)の補色の求め方
- 赤(#ED1A3D)をRGB配列に変換
各要素を [ED, 1A, 3D] という要素に分割し、それを10進数表記の [237, 26, 61] に変換する。これが求めたい色のRGB配列となる
- 最大値と最小値の合計を算出
上記の例なら最大値は237、最小値は26なので最大値+最小値=263となる。これが補色を求めるときのキーポイントになるので重要
- その値からRGBの各要素を引く
今求めた263からRGBの各要素を引いてあげる。その結果は [26, 237, 202] になるので、16進数表記に直すと補色は #1aedca だよねとなる。
▼ ある色(下)とその補色(上)
補色を求めるのはシンプルだけど手順が多いです。
ある色の補色を求めるJavaScriptコード例
ということで本題のJSコードについて。
先ほどの手順をコードに書き起こしてみます。
▼ このような関数で補色を求められる
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function invertColor(hex){ const rgb = hex.match( /[0-9a-fA-F]{1,2}/g ).reduce((p,c)=>{ p.push(parseInt(c,16)); return p; }, []); const minmax = Math.min(...rgb)+Math.max(...rgb); return rgb.reduce((p,c)=>{ p += (minmax-c).toString(16).padStart(2,'0'); return p; }, '#') } |
▼ 色々な色の補色を計算してみた
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/// 赤の補色は? invertColor('#ed1a3d'); /// => '#1aedca' /// 緑の補色は? invertColor('#008000') /// => '#800080' /// 青の補色は? invertColor('#0067C0') /// => '#c05900' /// 黒の補色は? invertColor('#000000') /// => '#000000' /// 白の補色は? invertColor('#ffffff') /// => '#ffffff' |
▼ 上記コードのreduce関数の解説
このような感じで補色の算出が可能。
僕自身もそうなんですが、補色と反転色をごっちゃにしてました。なんか「白の補色は…黒かな?」みたいに考えてたけど、補色では彩度や明度は一定に保たれます。
混同しないように注意したいです。
補色を求める便利なライブラリも存在する
もちろんライブラリを使うという手もあります。
良さげなライブラリを列挙すると以下の通り
▼ GitHub : tttienthinh / colorGenerator
▼ GitHub : mster / prismaek
ただしライブラリの使用は1点注意があります。
それはライブラリ作者が補色のことを理解してないリスクです。先ほど書いたように反転色と補色を混同してるケースもあるかもしれません。
だからライブラリの過信は禁物です。
定義通りの補色を求められるかテストが必要
コード的な補色の求め方のまとめ
補色をコード的に求める場合。
ここまでのように以下の注意が必要です。
- 単純に色反転させるのはナンセンス
- 補色と反転色はまったく別物
- ライブラリを使う時も過信しすぎない
以上、JavaScriptで補色を求めるコード例でした。
自分も補色がこんな定義だと初めて知ったし、
誤った前提でコードを書かないように注意です。