1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1人フロントエンドAdvent Calendar 2024

Day 11

透過色を利用したときに表示される色を計算する

Posted at

以下の画像は#50E3D2の背景に#FFFFFFを80%透過させた前景を被せたものです。

Group 1.png

全景の部分に表現されている色は何色になるのでしょうか。

スポイトで色を取り出してみると、#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%の透過度を与えます。
Group 2.png

この表示された色はスポイトで取ると#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}$の値を切り上げすれば同じようになります。

これで、前景色と背景色が透過度を持つ場合に表示される色について求められるようになりました。ツールを使えば簡単にわかる値ですが、計算方法を知ることでより色への理解をより深められたと思います。

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?