This World

Mixed & Blended

Hi, I'm Wei

@wgao19

🗿

There should be a CSS property that does that

🤔

Compositing & Blending

Compositing and Blending Module Level 1

compositing

blending

how shapes combine
based on the alphas of each pixel

how colors mix
in the areas where shapes overlap

Blending

section 10 of the specs

backdrop

The backdrop is the content behind the element and is what the element is composited with.

source

source is the incoming element being blended, composited and then rendered

blending function

B(Cb, Cs)

when backdrop is opaque

Cs = B(Cb, Cs)

Cr = (1 - ab) x Cs + ab x B(Cb, Cs)

  • Cr, Cs, Cb - resulting color, source color, backdrop color
  • blending modes specify B(Cb, Cs)
  • ab - alpha of backdrop

blending modes

multiply & screen

multiply

B(Cb, Cs) = Cb x Cs

"darkens" the graphics

🤔

CSS Color Space

CSS Color Module 4
CSS uses the

sRGB color space

#42355e

rgb(66, 53, 94)

#42355e

rgb(66, 53, 94)

rgb(26%, 21%, 37%)

multiply

rgb(65%, 70%, 90%)

rgb(100%, 70%, 20%)

_

rgb(65%, 49%, 18%)

intuitions ✌️

🖤 multiply 🦄 = 🖤

⚪️ multiply 🦄 = 🦄

🦑 multiply 🦄 = 🦄 multiply 🦑

💩 multiply 🦄 = 🐴

screen

complement of multiply

⚫️ screen 🔮 = 🔮

⚪️ screen 🔮 = ⚪️

🦑 screen 🦄 = 🦄 screen 🦑

Play with multiply and screen

CodePen Template

hard-light & overlay

hard-light

source is dark -> darkens backdrop

source is bright -> brightens backdrop

overlay

backdrop is dark -> darkens source

backdrop is bright -> brightens source

commuting operation with hard-light

Original pen by Louis Hoebregts, Yuan Chuan
Pen by Dudley Storey

hard-light

              HardLight(Cb, Cs) = 
              if(Cs <= 0.5)
                  B(Cb, Cs) = Multiply(Cb, 2 x Cs)
              else
                  B(Cb, Cs) = Screen(Cb, 2 x Cs - 1)
            

Case Cs <= 0.5

B(Cb, Cs) = Multiply(Cb, 2 x Cs)

B(Cb, Cs) = 2 x Cb x Cs

  • When the source color is dark, it almost always darkens the backdrop.
  • Whether it darkens the source or not, depends on backdrop.

Case Cs > 0.5

B(Cb, Cs) = Screen(Cb, 2 x Cs - 1)

B(Cb, Cs) = 2 x (Cb + Cs - Cb x Cs) - 1

  • When the source color is bright, it brightens the backdrop, justify
  • Whether it brightens the source or not, depends on backdrop, justify
When the source color is bright, it brightens the backdrop.
            Proof. 

            Hard light case Cs > 0.5:

            B(Cb, Cs) = Screen(Cb, 2 * Cs - 1)
                      = 2 * (Cb + Cs - Cb * Cs) - 1 

            Comparing with Cb, want to know if 2(Cb + Cs - Cb * Cs) - 1 - Cb > 0

            LHS = Cb + 2 * Cs - 2 * Cb * Cs - 1
                = Cb * (1 - 2 * Cs) - (1 - 2 * Cs)
                = (Cb - 1) * (1 - 2 * Cs)

            Since Cs > 0.5, 2 * Cs > 1, therefore 1 - 2 * Cs < 0;
            Cb - 1 <= 0 because Cb <= 1

            Hence LHS >= 0 and the conclusion is it will always brighten the backdrop.

            QED.
          
go back
Whether it brightens the source or not, depends on backdrop.
            Proof.

            Hard light case Cs > 0.5:

            B(Cb, Cs) = Screen(Cb, 2 * Cs - 1)
                      = 2 * (Cb + Cs - Cb * Cs) - 1 

            Comparing with Cs, want to know if 2(Cb + Cs - Cb * Cs) - 1 - Cs > 0

            Following similar factorization with the previous proof and we come to
            LHS = (Cs - 1) * (1 - 2 * Cb)

            Now we know that Cs - 1 <= 0 because Cs <= 1.
            However, whether the other term is >0 or not is unknown.

            If Cb > 0.5, then 2 * Cb > 1 and 1 - 2 * Cb < 0. 
            In this case the final product is >= 0, which implies it brightens the source.
            Otherwise, the result is reversed.

            QED.
          
go back
The effect is similar to shining a harsh spotlight on the backdrop.
  • Hard light tries to preserve the highlights and shadows in both backdrop and source.
  • But since the operation is first conditioned on the source, it prioritizes the texture of the source.

Hard light is not symmetric

And the commuted operation is overlay

Overlay(Cb, Cs) = Hardlight(Cs, Cb)

Now it preserves the highlights and shadows of the backdrop first

because the condition now lands on backdrop

difference

B(Cb, Cs) = | Cb - Cs |

👀

  • normal
  • multiply
  • screen
  • darken
  • lighten
  • overlay
  • hard-light
  • difference
  • color-dodge
  • color-burn
  • soft-light
  • exclusion

"Separable Blend Modes"

R, G, B channels are computed separately

"Non-Separable Blend Modes"

  • hue
  • saturation
  • color
  • luminosity

reverse engineering

blending modes

useless skill unlocked️

The quick brown fox jumps over the lazy dog
  • --red: rgb(255, 67, 56); /* #ff4338 */
  • --orange: rgb(255, 107, 0); /* #ff6b00 */
  • --yellow: rgb(255, 200, 67); /* #ffc843 */
  • --green: rgb(5, 206, 124); /* #05ce7c */
  • --blue: rgb(0, 179, 227); /* #00b3e3 */
  • --magenta: rgb(218, 58, 179); /* #da3ab3 */
  • --orange: rgb(255, 107, 0);
  • --blue: rgb(0, 179, 227);
  • --??: rgb(0, ??, 0);
  • 107/255 * 179 / 255 = 0.29
  • 0.29 * 255 = 75
  • 75 = 0x4b
  • 🤔 #004b00?
  • 💩 luck omg

Chrome Bug

Colors aren't blending correctly when using `mix-blend-mode`

Great,

now I have a few questions.

Why is my fan blowing?

200px x 200px image && overlay

200 x 200 x 3 x (3 addition + 2 multiplications)

a lot of work for animations like this

Does it work on emojis?

Yes!

What about that NDS Switch?

not possible 😭

limited by blending modes

What's this cool looking font? 👀

Gilbert Color

x (correct me if I'm wrong)

multiply

I hope you had fun

References