10.2 Masking

After consulting with Claude Opus 4.5

Simple Mask Example

Original With Mask
<svg width="400" height="150">
  <defs>
    <mask id="circleMask">
      <rect width="100%" height="100%" fill="red"/>
      <circle cx="300" cy="75" r="50" fill="white"/>
    </mask>
  </defs>
  <rect x="10" y="25" width="180" height="100" fill="steelblue"/>
  <text x="100" y="145" text-anchor="middle" font-size="12">Original</text>
  <rect x="210" y="25" width="180" height="100" fill="steelblue" mask="url(#circleMask)"/>
  <text x="300" y="145" text-anchor="middle" font-size="12">With Mask</text>
</svg>

The mask has a red background (partially transparent, ~21% opacity) and a white circle at cx="300" (fully visible). The blue rectangle shows through both areas with different transparency levels.

Four Ways to Achieve the Same Mask Result

In this picture the steelblue rectangle is going to be masked. But here it is not masked yet.
<svg width="200" height="150" style="background-color:orange;">
  <rect x="50" y="25" width="100" height="100" fill="steelblue"/>
  <path d="M 60 30 L 100 70 L 130 40 Z" style="fill:red"/>
  <rect x="70" y="45" width="60" height="60" fill="none" stroke="red"/>
</svg>

Why additionaly orange background and red elements (triangle and empty square)?
- Orange background will show that masked areas become truly transparent (don't confuse transparent with white)
- Red elements will not be not masked — it proves the mask only affects the element it's applied to, not the entire bounding box area

There are four ways to produce the same visual result by masking with a circular shape in the center.
The differences depend on the choice of maskUnits and maskContentUnits.

Example maskUnits maskContentUnits Circle coordinates
1 objectBoundingBox (default) userSpaceOnUse (default) cx=100, cy=75, r=30
2 userSpaceOnUse userSpaceOnUse cx=100, cy=75, r=30
3 objectBoundingBox (default) objectBoundingBox cx=0.5, cy=0.5, r=0.3
4 userSpaceOnUse objectBoundingBox cx=0.5, cy=0.5, r=0.3
1. Default: maskUnits="objectBoundingBox", maskContentUnits="userSpaceOnUse"
<svg width="200" height="150" style="background-color:orange;">
  <defs>
    <mask id="mask1">
      <circle cx="100" cy="75" r="30" fill="white"/>
    </mask>
  </defs>
  <rect x="50" y="25" width="100" height="100" fill="steelblue" mask="url(#mask1)"/>
  <path d="M 60 30 L 100 70 L 130 40 Z" style="fill:red"/>
  <rect x="70" y="45" width="60" height="60" fill="none" stroke="red"/>
</svg>

Circle uses SVG canvas coordinates: cx=100 is center of rectangle (50 + 100/2), cy=75 is center (25 + 100/2).

2. maskUnits="userSpaceOnUse", maskContentUnits="userSpaceOnUse"
<svg width="200" height="150" style="background-color:orange;">
  <defs>
    <mask id="mask2" maskUnits="userSpaceOnUse" x="50" y="25" width="100" height="100">
      <circle cx="100" cy="75" r="30" fill="white"/>
    </mask>
  </defs>
  <rect x="50" y="25" width="100" height="100" fill="steelblue" mask="url(#mask2)"/>
  <path d="M 60 30 L 100 70 L 130 40 Z" style="fill:red"/>
  <rect x="70" y="45" width="60" height="60" fill="none" stroke="red"/>
</svg>

Mask boundary and content both use SVG canvas coordinates.
Note: Unlike Example 1 (which uses default maskUnits="objectBoundingBox"), here we must explicitly specify x="50" y="25" width="100" height="100" because maskUnits="userSpaceOnUse" requires the mask boundary to be defined in SVG canvas coordinates.

3. maskUnits="objectBoundingBox", maskContentUnits="objectBoundingBox"
<svg width="200" height="150" style="background-color:orange;">
  <defs>
    <mask id="mask3" maskContentUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.3" fill="white"/>
    </mask>
  </defs>
  <rect x="50" y="25" width="100" height="100" fill="steelblue" mask="url(#mask3)"/>
  <path d="M 60 30 L 100 70 L 130 40 Z" style="fill:red"/>
  <rect x="70" y="45" width="60" height="60" fill="none" stroke="red"/>
</svg>

Circle uses bounding box coordinates: cx=0.5 means center, r=0.3 means 30% of bounding box size.

4. maskUnits="userSpaceOnUse", maskContentUnits="objectBoundingBox"
<svg width="200" height="150" style="background-color:orange;">
  <defs>
    <mask id="mask4" maskUnits="userSpaceOnUse" x="50" y="25" width="100" height="100" maskContentUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.3" fill="white"/>
    </mask>
  </defs>
  <rect x="50" y="25" width="100" height="100" fill="steelblue" mask="url(#mask4)"/>
  <path d="M 60 30 L 100 70 L 130 40 Z" style="fill:red"/>
  <rect x="70" y="45" width="60" height="60" fill="none" stroke="red"/>
</svg>

Mask boundary uses SVG coordinates, but circle inside uses bounding box coordinates.

Summary