The CSS clip-path property draws a hard boundary – everything outside disappears. But what if you want content to gradually fade, dissolve through a pattern, or reveal itself through a shaped window? That’s where mask-image comes in.
I use mask-image more and more in my projects. It gives you control over visibility using gradients, images, and SVGs as mask layers. The result is soft fades, creative shapes, and effects that clip-path simply cannot produce.
What mask-image Does
The mask-image property works through the alpha channel. You provide an image (gradient, SVG, PNG) and the browser uses its transparency to determine what stays visible.
Black (opaque) areas of the mask = fully visible. Transparent areas = hidden. Everything in between creates partial transparency.
The mask CSS shorthand property hides an element (partially or fully) by masking or clipping the image at specific points. It combines mask-image with other mask sub-properties like mask-size, mask-position, and mask-composite.
The basic syntax looks like this:
.element {
-webkit-mask-image: linear-gradient(black, transparent);
mask-image: linear-gradient(black, transparent);
}You can use any CSS gradient function as the mask source. No external files needed.
Gradient Masks
Gradients are the most practical mask source. You already know linear-gradient(), radial-gradient(), and conic-gradient() from backgrounds. They work identically as masks, but instead of painting color, they control transparency.
A linear-gradient mask fading from black to transparent creates a smooth fade-out. A radial-gradient creates a spotlight or vignette. A conic-gradient creates a pie-chart style reveal.
Play with the controls below to see how each type behaves:
The dot-grid background behind the preview makes masked-away areas immediately obvious. Try switching to radial and pulling the fade-start slider up to create a vignette effect.
Image and SVG Masks
Gradients are convenient, but SVG and image masks let you create arbitrary shapes. Any SVG path becomes a mask source through an inline data URI or external file reference.
The key related properties:
mask-size– works likebackground-size(e.g.,contain,cover, or pixel values)mask-position– works likebackground-positionmask-repeat– set tono-repeatfor single masks, or let it tile
.element {
-webkit-mask-image: url('mask-shape.svg');
mask-image: url('mask-shape.svg');
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}Click a shape below to apply it as a mask, then experiment with mask-size and mask-repeat to see how the sub-properties affect the result:
Each shape is a simple SVG <path> or <polygon> encoded as a data URI. The gradient underneath bleeds through whatever the SVG shape defines as solid. This technique works well for avatars, decorative sections, and product image treatments.
Combining Multiple Masks with mask-composite
You can stack multiple mask layers, just like multiple backgrounds. The mask-composite property controls how those layers interact. Four modes are available:
add– union of both masks (default). All masked areas from both layers are visible.subtract– the second mask cuts away from the firstintersect– only the overlap between both masks remains visibleexclude– only non-overlapping areas are visible
The standard mask-composite values (add, subtract, intersect, exclude) differ from the -webkit-mask-composite values (source-over, source-out, source-in, xor). Always include both for cross-browser compatibility.
Switch between modes below to see how a radial gradient mask and a diagonal stripe mask combine:
The intersect mode is especially useful for creating complex shapes from simple gradients. Two basic gradients combined with intersect can produce shapes that would be tedious to draw manually.
Fade-Out Scroll Edges
Fading the edges of scrollable containers is probably the mask-image use case I run into most. Instead of a hard cut-off, content dissolves at the boundary, hinting that more is available above or below.
Apply a linear-gradient mask that goes from transparent at the edges to black in the middle. The gradient stop positions control how far the fade extends.
.scrollable {
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0px,
black 40px,
black calc(100% - 40px),
transparent 100%
);
mask-image: linear-gradient(
to bottom,
transparent 0px,
black 40px,
black calc(100% - 40px),
transparent 100%
);
}Try adjusting the fade size and position in the terminal-styled demo below:
Navigation menus, dropdown lists, chat windows, sidebars. It works anywhere content overflows a container. No JavaScript needed for the mask itself, just CSS.
Image Hover Reveal Effect
One of my favorite mask-image tricks is the flashlight reveal. A grayscale layer sits underneath, and a color layer on top is masked by a radial-gradient that follows the mouse cursor. The result: a spotlight that reveals the full-color version only where you hover.
The JavaScript updates mask-image on every mousemove, repositioning the radial gradient to follow the cursor:
container.addEventListener('mousemove', function(e) {
var rect = container.getBoundingClientRect();
var x = ((e.clientX - rect.left) / rect.width) * 100;
var y = ((e.clientY - rect.top) / rect.height) * 100;
colorLayer.style.maskImage =
'radial-gradient(circle 120px at ' + x + '% ' + y + '%, black 0%, transparent 100%)';
});Move your mouse over the area below. Toggle between Flashlight and Wipe modes, and adjust the reveal size:
The amber glow ring at the edge of the reveal circle is itself a mask trick. A separate layer uses a ring-shaped radial gradient mask, creating a glowing border effect without any box-shadow or filter.
Text Knockout with mask-image
Text reveals are where mask-image really shines. A diagonal gradient mask sweeps across, progressively revealing characters. The trick: set mask-size: 300% 100% and animate mask-position from one end to the other.
The shimmer trail you see behind the sweep edge is a second layer. It uses a narrow gradient on the same animation timing, blended with mix-blend-mode: screen.
.text-reveal {
-webkit-mask-image: linear-gradient(110deg, black 0%, black 0%, transparent 10%, transparent 100%);
mask-image: linear-gradient(110deg, black 0%, black 0%, transparent 10%, transparent 100%);
-webkit-mask-size: 300% 100%;
mask-size: 300% 100%;
animation: sweep 3s ease-in-out forwards;
}
@keyframes sweep {
from { mask-position: 100% 0; }
to { mask-position: 0% 0; }
}Hit play to see the cinematic text reveal in action:
I’ve used this on hero sections and portfolio headers. The gradient text underneath (background-clip: text) adds another layer of depth.
mask-image vs clip-path
Both properties hide parts of an element. They solve different problems, though:
| Aspect | mask-image | clip-path |
|---|---|---|
| Edge type | Soft fades and gradients | Hard edges only |
| Source | Gradients, images, SVG | Shapes, polygons, SVG path |
| Multi-layer | Yes, with mask-composite | No |
| Animation | Gradient positions, mask-size | Shape points, inset values |
| Transparency | Partial transparency supported | Binary: visible or hidden |
| Use case | Fades, reveals, texture masks | Geometric shapes, cutouts |
Use clip-path when you need crisp geometric shapes. Use mask-image when you need soft transitions, pattern-based visibility, or multiple composited layers.
Browser Support
mask-image reached Baseline status in December 2023. All modern browsers support it fully.
Always include both the -webkit-mask-image prefixed version and the standard mask-image property. Older Safari versions (before 15.4) only support the prefixed variant. The same applies to mask-size, mask-position, mask-repeat, and mask-composite (which uses -webkit-mask-composite with different values like source-over instead of add).
FAQs
Common questions about the CSS mask-image property:
mask-image uses gradients or images to control element visibility through the alpha channel, allowing soft fades and partial transparency. clip-path uses geometric shapes to create hard-edged cutouts. Use mask-image for gradual transitions and clip-path for crisp shapes.mask-image is supported in Chrome 120+, Firefox 53+, Safari 15.4+, and Edge 120+, older Safari versions require the -webkit-mask-image prefix. Always include both for maximum compatibility.linear-gradient(), radial-gradient(), and conic-gradient() all work as mask-image values. Black areas in the gradient make the element visible, and transparent areas hide it. This is the most common approach since it requires no external files.mask-composite controls how multiple mask layers combine. The four standard values are add (union), subtract (cut second from first), intersect (overlap only), and exclude (non-overlapping areas only). Note that -webkit-mask-composite uses different value names: source-over, source-out, source-in, and xor.mask-image value itself. However, you can animate mask-position and mask-size to create smooth reveal effects, or update mask-image via JavaScript on events like mousemove for interactive effects.mask-mode property determines how the mask source is interpreted. With alpha (the default for images and gradients), the alpha channel controls visibility. With luminance, bright areas (white) are visible and dark areas (black) are hidden. Luminance mode is useful when working with SVG masks referenced via url().Summary
mask-image fills a gap that no other CSS property covers: gradient-based, partial-transparency control over what the user sees. I reach for it whenever a hard-edged clip-path would look too blunt. Scroll fades, hover spotlights, text sweeps, pattern overlays.
Browser support has been solid since December 2023. Include the -webkit- prefix alongside the standard property, match the -webkit-mask-composite value names, and you are set.

