How CSS opacity works

Everything we see on the browsers comes from pixels represented by an RGB value(or HSV, HSB, etc.)

For two squares below, if I uncomment the transform: translateX(-200px); a new “merged” square will be generated. What would the color of that square roughly be as an RGB value?

(Why would we even care what the value is? Well if we need transforming raw RGB data between client and server, paint the rendering result from <Canvas /> to <img /> or process images, then the value matters.)

The answer is RGB(230, 25, 48), although it is possible that the value will change a little bit depending on your environment.

To figure out what happened, let’s start from the first square.

The first square initially has color RGB(255, 26, 26), which comes from blending the page’s background RGB(255, 255, 255) with the square’s color.

Let’s call the first square SRC and page background DST.

The result’s value of R comes from

SRC.R * SRC.Opacity + DST.R * (1 — SRC.Opacity) ,

same as B and G. When Opacity is 1, the result purely comes from SRC, vice versa.

So, we got the result RGB(255, 26, 26) by:

R: 255 * 0.9 + 255 * 0.1 .

G: 0 * 0.9 + 255 * 0.1 .

B: 0 * 0.9 + 255 * 0.1 .

Back to the weird RGB(230, 25, 48), by blending SRC — RGB(0, 0, 255) opacity 0.1 with DST — RGB(255, 26, 26), we get the result:

(0 * 0.1 + 255 * 0.9, 25 * 0.1 + 26 * 0.1, 255 * 0.1 + 26 * 0.9)

In conclusion: as mentioned in W3C CSS specification, opacity indicates how to blend the target with existing content, and browsers help us deal with alpha blending automatically.