w3tweaks.com · CSS Tutorial

CSS mask

Fade edges, spotlight reveals, text shapes — all with gradient masks.

Tab 1

Live Mask Builder

Choose a mask type and adjust the parameters. The CSS updates live. Key insight: black = visible, white/transparent = hidden.

20%
80%
Preview Black = visible · Transparent = hidden
mask-image: linear-gradient(to bottom, black 20%, transparent 80%);
-webkit-mask-image: linear-gradient(to bottom, black 20%, transparent 80%);
mask vs clip-path — Which to Use?
❌ clip-path — Hard Edge
Diagonal cut
.el { clip-path: polygon(0 0,100% 0,100% 70%,0 100%); }

Hard, sharp edge. Either fully visible or fully hidden. No partial transparency. Use for shapes.

✅ mask — Soft Fade
Soft diagonal
.el { mask-image: linear-gradient(to bottom right,black 40%,transparent 70%); }

Soft, graduated fade. Pixels can be partially visible. Use for fades, spotlight, feathered edges.

The golden rule: In a CSS mask, black = fully visible, transparent = fully hidden, and anything in between creates partial transparency. This is the opposite of how most people intuitively think about it — "the mask is the shape you can see through."
Tab 2

6 Real Patterns

These are the production use cases. Scroll the first demo, hover the spotlight, click the wipe reveal.

↔️ Scroll Container Edge Fade
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
.scroll {
  overflow-x: auto;
  mask: linear-gradient(to right,
    transparent, black 15%,
    black 85%, transparent)
;
}

Scroll left/right. The mask fades the edges, hinting at more content. The gradient stops control how far the fade extends.

✍️ Text Edge Fade
MASKED
.text {
  mask-image: linear-gradient(
    to right,
    transparent, black 20%,
    black 80%, transparent
  )
;
}

The text fades at both edges — useful for marquee/ticker text or truncated content that hints at more.

🔦 Spotlight Hover Effect
Move mouse over me
.overlay {
  background: rgba(0,0,0,.85);
  mask: radial-gradient(
    circle 40px at var(--x) var(--y),
    black 40%, transparent 70%
  )
;
}

A radial gradient mask centered at the cursor position creates a spotlight. Only mask-position changes on mouse move — no JS color math needed.

↗️ Diagonal Section Fade
.section {
  mask: linear-gradient(
    to bottom right,
    black 40%, transparent 70%
  )
;
}

Softer than clip-path: polygon() — the diagonal edge feathers instead of cutting sharply. Ideal for overlapping hero sections.

▶️ Wipe Reveal Animation
Click to reveal
Revealed! ✓
@keyframes wipe {
  from { mask: linear-gradient(to right,black 0%,transparent 0%); }
  to { mask: linear-gradient(to right,black 100%,transparent 100%); }
}

Animating the gradient stop position in the mask creates a smooth wipe reveal — no JavaScript, no clip-path vertex counts.

🌑 Radial Vignette
.img {
  mask: radial-gradient(
    ellipse at center,
    black 40%, transparent 80%
  )
;
}

A radial mask fades the edges of an image or section inward — the classic vignette effect without a separate overlay element.

Tab 3

mask-composite & Critical Gotchas

When you stack multiple mask layers, mask-composite controls how they combine. And the Safari prefix uses completely different value names.

Alpha vs Luminance Masks
mask-mode: alpha (default for gradients)
/* Transparency of mask = visibility */
mask-image: linear-gradient(
  to right,
  rgba(0,0,0,0), ← 0% alpha = hidden
  rgba(0,0,0,0.5),← 50% alpha = semi
  rgba(0,0,0,1) ← 100% alpha = visible
)
;

Alpha channel controls visibility. Use for PNG masks and CSS gradients (default behavior).

mask-mode: luminance (default for SVG <mask>)
/* Brightness of mask = visibility */
mask-image: linear-gradient(
  to right,
  black, ← black = hidden
  gray, ← gray = semi
  white ← white = visible
)
;
mask-mode: luminance;

Brightness controls visibility. Use for SVG <mask> elements. Black=hidden, white=visible.

mask-composite — Combining Multiple Mask Layers
add

Both mask layers are combined — the element shows through anywhere either mask allows it.

subtract

The top layer is subtracted from the bottom — overlap areas are hidden, creating a punch-out effect.

intersect

Only where both masks overlap is visible — useful for complex shapes from simple gradients.

exclude

XOR — the overlap is hidden while non-overlapping areas show. Creates a ring/donut effect.

⚠️ The -webkit-mask-composite Naming Mismatch
Critical gotcha: The standard mask-composite values and the prefixed -webkit-mask-composite values use completely different names. You must include both with the correct names — they're not the same strings.
Effect Standard: mask-composite Prefixed: -webkit-mask-composite
Combine bothaddsource-over
Punch throughsubtractsource-out
Overlap onlyintersectsource-in
XOR ringexcludexor
/* Always include both — different value names */
.el {
  mask-composite: subtract; /* standard */
  -webkit-mask-composite: source-out; /* Safari prefix */
}
Always include -webkit- prefixes for all mask properties:
mask-image-webkit-mask-image
mask-size-webkit-mask-size
mask-repeat-webkit-mask-repeat
mask-position-webkit-mask-position
mask-composite-webkit-mask-composite (different value names!)
mask-mode-webkit-mask-mode
The shorthand mask-webkit-mask
Read the tutorial