How SVG Luminance-Based Masking Works
Luminance-based masking in SVG uses the brightness and opacity values
of graphic elements inside a <mask> element to
determine the transparency of a target shape. Pure white areas in the
mask leave the masked graphic completely opaque, pure black areas make
it fully transparent, and shades of grey or colors create varying levels
of semi-transparency. This article explains the underlying mathematics,
the role of color and alpha channels, and how the browser calculates
final visibility.
The Luminance Calculation Formula
When an SVG element references a <mask> element,
the rendering engine converts the color of every pixel inside that mask
into a single grayscale luminance value. SVG follows the standard ITU-R
BT.709 color conversion formula to calculate perceived luminance (\(Y\)):
\[Y = 0.2126 \times R + 0.7152 \times G + 0.0722 \times B\]
In this calculation, the red (\(R\)), green (\(G\)), and blue (\(B\)) channels are normalized between 0.0 and 1.0. Because the human eye is most sensitive to green light and least sensitive to blue light, the green channel contributes the most significantly to the final opacity of the masked object.
Integrating the Alpha Channel
Luminance is not evaluated in isolation; it is multiplied by the opacity (alpha channel) of the mask element. The effective mask coefficient (\(M\)) applied to the target element’s alpha channel is calculated as:
\[M = Y \times A\]
Where \(A\) is the computed alpha
value of the mask pixel. If a mask element has a fill of
#ffffff (white) but an opacity="0.5", the
effective luminance calculation results in an opacity multiplier of 0.5
for the masked target.
How Color Values Affect Opacity
Because of the weighted formula, different colors with the same numeric channel values produce vastly different levels of transparency:
- Pure White (
#ffffff): Yields a luminance of 1.0. The underlying graphic remains 100% opaque. - Pure Black (
#000000): Yields a luminance of 0.0. The underlying graphic becomes completely invisible. - Midtone Grey (
#808080): Yields a luminance of approximately 0.5. The underlying graphic becomes 50% translucent. - Pure Green (
#00ff00): Produces high visibility with a luminance value of ~0.715. - Pure Red (
#ff0000): Produces low visibility with a luminance value of ~0.213. - Pure Blue (
#0000ff): Produces very low visibility with a luminance value of ~0.072.
Implementing a Luminance Mask in SVG
By default, an SVG <mask> element has its
mask-type CSS property set to luminance. The
mask is defined within a <defs> block and referenced
via the mask attribute on the target shape:
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="fade" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="white" />
<stop offset="100%" stop-color="black" />
</linearGradient>
<mask id="luminanceMask">
<!-- The gradient dictates opacity from 100% to 0% -->
<rect x="0" y="0" width="200" height="200" fill="url(#fade)" />
</mask>
</defs>
<!-- This rectangle fades out horizontally based on the mask's luminance -->
<rect x="0" y="0" width="200" height="200" fill="royalblue" mask="url(#luminanceMask)" />
</svg>In this example, the linear gradient transitions from white to black, creating a smooth horizontal fade on the target rectangle without modifying the target element’s own fill or opacity attributes directly.