以下の画像は#50E3D2
の背景に#FFFFFF
を80%透過させた前景を被せたものです。
全景の部分に表現されている色は何色になるのでしょうか。
スポイトで色を取り出してみると、#50E3D2
の明度が下がったような色(#DCF9F6
)になりました。
このような前景に透過色を配置したときの色を計算によって求めてみましょう。
この記事は主にブラウザの動作、CSSにおける色について考えています。
他の領域では異なる計算になる可能性があることに注意してください。
CSSの重ね合わせコンテキストをもとに考えていきます。CSSの重ね合わせコンテキストはHTML要素の三次元を概念化したものです。
W3Cでは重ね合わせコンテキストの不透明度についての扱いについてが決められています。これによると透明度の計算はシンプルなアルファ合成で行われるようです。
シンプルなアルファ合成は以下のように計算されます。
\begin{align}
B_r, B_g, B_b ・・・背景のRGB \\
B_a ・・・背景の透明度 \\
F_r, F_g, F_b ・・・前景のRGB \\
F_a ・・・前景の透明度 \\
\end{align}
\begin{align}
R_r = (1 - F_a) \times B_r\times B_a + F_r\times F_a \\
R_g = (1 - F_a) \times B_g\times B_a + F_g\times F_a \\
R_b = (1 - F_a) \times B_b\times B_a + F_b\times F_a \\
R_a = 1 - (1 - F_a) \times (1 - B_a)
\end{align}
$R_{r,g,b,a}$は最終的に表示される色です。今回は$B_a = 1$を考えているので、さらに以下のように変換できます。
\begin{align}
R_r = (1 - F_a) \times B_r + F_r\times F_a \\
R_g = (1 - F_a) \times B_g + F_g\times F_a \\
R_b = (1 - F_a) \times B_b + F_b\times F_a \\
R_a = 1
\end{align}
この色が透過色を利用したときに表示される色を求めるものです。
最初の例に当てはめて計算してみましょう。
背景色は#50E3D2
なのでrgb
表記ではrgb(80 227 210)
です。前景色は#FFFFFF
の80%なのでrgb(255 255 255 / .8)
です。
$F_{r,g,b} \times F_a$は$204$です。
$(1 - F_a) \times B_r$は$16$、$(1 - F_a) \times B_g$は$45.4$、$(1 - F_a) \times B_b$は$42$になります。
これらを代入すると、rgb(220 249, 246)
が得られました(小数点は四捨五入しています)。
これはHEX形式にすると#DCF9F6
なので、最初にスポイトで取った値と同じになりました。
最後に、背景色も透過しているケースを考えてみます。前景色はそのままで、背景色に70%の透過度を与えます。
この表示された色はスポイトで取ると#E6FBF9
でした。
\begin{align}
R_r = (1 - F_a) \times B_r\times B_a + F_r\times F_a \\
R_g = (1 - F_a) \times B_g\times B_a + F_g\times F_a \\
R_b = (1 - F_a) \times B_b\times B_a + F_b\times F_a \\
R_a = 1 - (1 - F_a) \times (1 - B_a)
\end{align}
先ほど確認した上記の数式にすべての値を当てはめると以下のようになります。
\begin{align}
R_r = (1 - 0.8) \times 80\times 0.7 + 255\times 0.8 = 215.2 \\
R_g = (1 - 0.8) \times 227\times 0.7 + 255\times 0.8 = 235.78 \\
R_b = (1 - 0.8) \times 210\times 0.7 + 255\times 0.8 = 233.4 \\
R_a = 1 - (1 - 0.8) \times (1 - 0.7) = 0.94
\end{align}
透過度が$1$になるように値を調整すると、rgb(229 251 248)
になります($R_{r,g,b}$それぞれの値を$R_a$で割っています)。
HEX形式に書き直すと、#E5FBF8
です。これはスポイトで取った#E6FBF9
とRedとBlueが$1$ずれた値になります。この誤差はスポイト機能を実装したアプリとの計算方法の違いから生まれたものだと考えています。例えば、透過度が1になるように値を計算する際に$R_{r,g,b}$の値を切り上げすれば同じようになります。
これで、前景色と背景色が透過度を持つ場合に表示される色について求められるようになりました。ツールを使えば簡単にわかる値ですが、計算方法を知ることでより色への理解をより深められたと思います。