Collapsing Layered Transparency

Two semitransparent overlays often end up stacked on top of an image in otherwise straightforward page code, frequently with identical RGB values for their background-color. The result may be perfectly acceptable visually — sometimes the cumulative tint is just what the design calls for. But it leaves a code smell: the second layer exists not because the design treats it as a distinct element but because the first layer’s opacity was never raised to achieve the same effect.

Replacing two such layers with a single equivalent one is straightforward. The combined alpha comes from the standard compositing formula used for the add operation in mask compositing: given two layers with alphas a0 and a1, the resulting alpha is

a0 + a1 - a0⋅a1

An interactive side-by-side comparison lets you adjust a0 and a1 for the two-layer version and shows it against a single layer whose alpha is a0 + a1 - a0⋅a1. Removing the background image entirely makes the two panels look identical; with an image underneath they may appear subtly different in places where the image is lighter or darker. When you cannot see them side by side — switching back and forth between the two-layer and one-layer versions — no difference is perceptible.

Generalizing to N Layers

The same operation generalizes beyond two layers. The strategy is to compute the equivalent layer of the bottom two, then combine that result with the layer immediately above it, continuing upward until one layer remains:

Diagram. Illustrates how a bunch of semitransparent layers of various alphas are reduced to a single one. We start by taking the first two from the bottom and computing their equivalent, then we take this result and the third layer from the bottom and combine them into a single layer and so on.
Reducing multiple semitransparent layers to a single one.

This incremental combination produces a single layer with the same composited appearance as the full stack, no matter how many layers are involved.

Overlaying on an Opaque Background

The same reduction works when the bottom layer is a solid color. For a solid bottom layer c0 under a semitransparent top layer c1 with alpha a, the equivalent solid color is computed per channel:

ch0 + (ch1 - ch0)*a

In that formula, ch0 stands for a channel (red, green, or blue) of the bottom layer, ch1 is the corresponding channel of the top layer, and a is the top layer’s alpha. The equivalent is a single solid background that matches the two-layer result under both normal and wide gamut viewing conditions.

A CSS preprocessor makes this trivial to encode; in Sass the per-channel computation is a small mixin:

/* per channel function */
@function res-ch($ch0, $ch1, $a) {
  @return $ch0 + ($ch1 - $ch0)*$a
}

@function res-col($c0, $c1, $a) {
  $ch: 'red' 'green' 'blue'; /* channel names */
  $nc: length($ch); /* number of channels */
  $ch-list: ();

  @for $i from 0 to $nc {
    $fn: nth($ch, $i + 1);
    $ch-list: $ch-list, 
      res-ch(call($fn, $c0), call($fn, $c1), $a);
  }

  @return RGB($ch-list)
}

An interactive demo that lets you pick RGB values and an alpha for the top layer confirms the math. Yet there is a caveat: depending on your device, operating system, and browser, the two panels may appear identical or slightly different. The formula is correct — the discrepancy lies in how browsers handle the two-layer compositing case, not in the one-layer result.

Where the Difference Shows Up

Feedback on a simplified test case shows the pattern across platforms:

  • Mobile browsers agree across Android and iOS: the two panels always match.
  • Firefox matches regardless of operating system.
  • Windows browsers nearly always match, although both Chrome and Chromium Edge have been reported to occasionally render the two panels differently.
  • WebKit browsers on macOS and Linux show mixed results, with the panels slightly different in most cases — though switching to an sRGB color profile can eliminate the difference. On a two-monitor setup, moving the window from one display to another can change whether the panels appear different.

In a real-world page, the difference is tiny. Designers and developers rarely inspect two variants side by side, so the discrepancy is unlikely to surface in normal use — much like the small, ordinary variations in how the same solid background color renders across different operating systems and screens. Perceptual differences between individual viewers add more variation on top of that. The one-layer equivalent is the correct way to express the stacked-transparency result, and any residual mismatch is a browser rendering detail rather than a flaw in the compositing math.