Fading images with CSS masks
A fade baked into an image works on exactly one background. A CSS mask keeps the source image intact and decides which pixels should be visible when the page is rendered.
That makes masks useful for soft edges, scroll hints, cutouts, and one-colour icons. The MDN CSS masking guide covers the complete set of properties.
Start with an alpha fade
.photo {
mask-image: linear-gradient(
to bottom,
black 70%,
transparent
);
}
With the normal alpha-mask behaviour, opaque pixels reveal the element and transparent pixels hide it. The colour black is not painted onto the photo; only its alpha matters here.
The same technique can hint that a horizontal row continues:
.logo-row {
overflow-x: auto;
mask-image: linear-gradient(
to right,
transparent,
black 2rem,
black calc(100% - 2rem),
transparent
);
}
Keep another visible cue for scrolling. A fade is decoration, not an instruction manual.
Use an SVG as a recolourable icon
A mask supplies the shape while the background supplies the colour:
.icon {
width: 2rem;
height: 2rem;
color: red;
background: currentColor;
mask: url("/icons/search.svg") center / contain no-repeat;
}
This is handy for a monochrome icon that should follow text colour. It is a poor fit for a multicolour illustration, because the mask keeps visibility information rather than the image’s original paint.
The longhand version is easier to debug:
.logo-shape {
mask-image: url("/mask.svg");
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
background: blue;
}
Masking changes paint, not layout
The element still owns its rectangular box even where the mask makes it invisible. Test pointer targets and keyboard focus if the masked element is interactive.
I also avoid using a mask to carry essential information. A missing decorative fade is harmless; a missing control is not.
Make the effect optional
.photo {
display: block;
}
@supports (mask-image: linear-gradient(black, transparent)) {
.photo {
mask-image: linear-gradient(black 80%, transparent);
}
}
For a hard circle, border-radius is simpler. For a hard polygon, clip-path usually reads better. I reach for a mask when partial transparency is the actual effect—not merely because the property can do more.
Enjoyed reading this?
If you found this article helpful, consider supporting my writing. Every little bit helps keep this blog going.
Related articles
- Making Links Easy to Recognize
Make links recognisable with underlines, clear focus states, useful text, and behaviour that does not surprise the reader.
- Smoother Page Changes With View Transitions
Use the View Transition API for same-page state changes and progressive cross-document animation on a normal multi-page site.
- When to use CSS clip-path or mask
Choose between CSS clip-path and mask by deciding whether the element needs a hard boundary or levels of transparency.