What You'll Learn
Control element transparency using mask-image
Create gradient masks for fade effects and vignettes
Apply SVG masks for complex shapes beyond clip-path
Build repeating pattern masks (stripes, dots, checkerboards)
Understand mask compositing and layering
Combine masks with animations for reveal effects
Distinguish between masks, clip-path, and opacity
Introduction to CSS Masks
CSS masks control an element's transparency using images or gradients as a "mask layer." Unlike clip-path which creates hard edges, masks support gradual transparency through grayscale values: black areas are fully visible, white is fully transparent, and grays create partial transparency.
Masks are perfect for fade effects, soft-edge clipping, pattern overlays, and complex transparency effects that clip-path and opacity cannot achieve.
Black = Visible, White = Transparent: In mask images, black (#000) keeps content visible, white (#fff) makes it transparent. This is the opposite of typical alpha channels where white means opaque.
Gradient Masks - Fade Effects
Linear and radial gradients create smooth fade effects, vignettes, and soft edges.
/* Linear gradient masks */
/* Horizontal fade (left visible, right transparent) */
.fade-horizontal {
-webkit-mask-image: linear-gradient(to right, black, transparent);
mask-image: linear-gradient(to right, black, transparent);
}
/* Vertical fade (top visible, bottom transparent) */
.fade-vertical {
-webkit-mask-image: linear-gradient(to bottom, black, transparent);
mask-image: linear-gradient(to bottom, black, transparent);
}
/* Fade both edges (center visible, edges transparent) */
.fade-edges {
-webkit-mask-image: linear-gradient(to right, transparent, black 20%, black 80%, transparent);
mask-image: linear-gradient(to right, transparent, black 20%, black 80%, transparent);
}
/* Radial gradient masks */
/* Circular vignette */
.vignette {
-webkit-mask-image: radial-gradient(circle at center, black 50%, transparent 80%);
mask-image: radial-gradient(circle at center, black 50%, transparent 80%);
}
/* Spotlight effect */
.spotlight {
-webkit-mask-image: radial-gradient(circle at 30% 30%, black 20%, transparent 60%);
mask-image: radial-gradient(circle at 30% 30%, black 20%, transparent 60%);
}
/* Soft circular mask */
.soft-circle {
-webkit-mask-image: radial-gradient(circle, black 40%, transparent 50%);
mask-image: radial-gradient(circle, black 40%, transparent 50%);
}
/* Practical examples */
/* Fade text at bottom of container */
.text-fade-bottom {
-webkit-mask-image: linear-gradient(to bottom, black 70%, transparent 100%);
mask-image: linear-gradient(to bottom, black 70%, transparent 100%);
}
/* Image gallery hover fade */
.gallery-item img {
-webkit-mask-image: linear-gradient(black, black);
mask-image: linear-gradient(black, black);
transition: mask-image 0.3s;
}
.gallery-item:hover img {
-webkit-mask-image: radial-gradient(circle, black 60%, transparent 80%);
mask-image: radial-gradient(circle, black 60%, transparent 80%);
}
Vendor Prefix Required: Always include -webkit-mask-image alongside mask-image for maximum browser compatibility, especially in Safari and older Chrome.
Pattern Masks - Repeating Effects
Repeating gradients create pattern masks: stripes, dots, waves, and geometric patterns.
/* Diagonal stripes */
.stripes {
-webkit-mask-image: repeating-linear-gradient(
45deg,
black 0px,
black 20px,
transparent 20px,
transparent 40px
);
mask-image: repeating-linear-gradient(
45deg,
black 0px,
black 20px,
transparent 20px,
transparent 40px
);
}
/* Dots pattern */
.dots {
-webkit-mask-image: radial-gradient(circle, black 30%, transparent 30%);
mask-image: radial-gradient(circle, black 30%, transparent 30%);
-webkit-mask-size: 30px 30px;
mask-size: 30px 30px;
}
/* Horizontal lines */
.lines-horizontal {
-webkit-mask-image: repeating-linear-gradient(
to bottom,
black 0px,
black 15px,
transparent 15px,
transparent 30px
);
mask-image: repeating-linear-gradient(
to bottom,
black 0px,
black 15px,
transparent 15px,
transparent 30px
);
}
/* Wavy pattern */
.waves {
-webkit-mask-image: radial-gradient(ellipse at top, transparent 50%, black 50%);
mask-image: radial-gradient(ellipse at top, transparent 50%, black 50%);
-webkit-mask-size: 40px 20px;
mask-size: 40px 20px;
}
/* Checkerboard */
.checkerboard {
-webkit-mask-image:
repeating-linear-gradient(0deg, black 0, black 20px, transparent 20px, transparent 40px),
repeating-linear-gradient(90deg, black 0, black 20px, transparent 20px, transparent 40px);
mask-image:
repeating-linear-gradient(0deg, black 0, black 20px, transparent 20px, transparent 40px),
repeating-linear-gradient(90deg, black 0, black 20px, transparent 20px, transparent 40px);
-webkit-mask-composite: source-in;
mask-composite: intersect;
}
/* Grid pattern */
.grid-pattern {
-webkit-mask-image:
repeating-linear-gradient(0deg, transparent, transparent 48px, black 48px, black 50px),
repeating-linear-gradient(90deg, transparent, transparent 48px, black 48px, black 50px);
mask-image:
repeating-linear-gradient(0deg, transparent, transparent 48px, black 48px, black 50px),
repeating-linear-gradient(90deg, transparent, transparent 48px, black 48px, black 50px);
}
mask-size: Control pattern scale with mask-size. Smaller values create denser patterns; larger values create more spacing.
SVG Masks - Complex Shapes
Use SVG images as masks for shapes more complex than clip-path can create, including icons, logos, and illustrations.
/* SVG shape masks using data URLs */
/* Star mask */
.star-mask {
-webkit-mask-image: url('data:image/svg+xml, ');
mask-image: url('data:image/svg+xml, ');
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}
/* Heart mask */
.heart-mask {
-webkit-mask-image: url('data:image/svg+xml, ');
mask-image: url('data:image/svg+xml, ');
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}
/* External SVG file */
.logo-mask {
-webkit-mask-image: url('/path/to/logo-mask.svg');
mask-image: url('/path/to/logo-mask.svg');
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
/* Repeating SVG pattern */
.icon-pattern {
-webkit-mask-image: url('/path/to/icon.svg');
mask-image: url('/path/to/icon.svg');
-webkit-mask-size: 50px 50px;
mask-size: 50px 50px;
-webkit-mask-repeat: repeat;
mask-repeat: repeat;
}
/* Icon with gradient fade */
.icon-fade {
-webkit-mask-image:
url('/path/to/icon.svg'),
linear-gradient(to bottom, black, transparent);
mask-image:
url('/path/to/icon.svg'),
linear-gradient(to bottom, black, transparent);
-webkit-mask-composite: source-in;
mask-composite: intersect;
}
SVG Fill Color: In mask SVGs, use fill="black" for visible areas and fill="white" or transparent for hidden areas. The SVG's fill color determines mask transparency.
Mask Properties - Size, Position, Repeat
Control how mask images apply to elements with sizing, positioning, and repeat properties, similar to background-* properties.
/* mask-size - Control mask dimensions */
mask-size: contain; /* Fit within element */
mask-size: cover; /* Cover entire element */
mask-size: 100px 100px; /* Fixed size */
mask-size: 50% 50%; /* Percentage of element */
/* mask-position - Position the mask */
mask-position: center; /* Center mask */
mask-position: top left; /* Keywords */
mask-position: 50% 50%; /* Percentages */
mask-position: 20px 30px; /* Pixel values */
/* mask-repeat - Control repetition */
mask-repeat: no-repeat; /* Single instance */
mask-repeat: repeat; /* Tile in both directions */
mask-repeat: repeat-x; /* Horizontal only */
mask-repeat: repeat-y; /* Vertical only */
mask-repeat: space; /* Space evenly */
mask-repeat: round; /* Stretch to fit */
/* mask-origin - Mask positioning box */
mask-origin: border-box; /* Include border */
mask-origin: padding-box; /* Exclude border (default) */
mask-origin: content-box; /* Only content area */
/* mask-clip - Mask painting area */
mask-clip: border-box; /* Paint including border */
mask-clip: padding-box; /* Exclude border */
mask-clip: content-box; /* Only content */
/* Complete example */
.masked-element {
-webkit-mask-image: url('/mask.svg');
mask-image: url('/mask.svg');
-webkit-mask-size: 200px 200px;
mask-size: 200px 200px;
-webkit-mask-position: center;
mask-position: center;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
/* Shorthand (experimental) */
mask: url('/mask.svg') center/200px no-repeat;
Like Background Properties: Mask properties work identically to their background-* equivalents, making them intuitive if you're familiar with background styling.
Animated Masks - Reveal Effects
Animate masks for wipe transitions, reveal effects, and dynamic transparency changes.
/* Wipe reveal animation */
@keyframes wipe-reveal {
from {
-webkit-mask-image: linear-gradient(to right, black 0%, black 0%, transparent 0%);
mask-image: linear-gradient(to right, black 0%, black 0%, transparent 0%);
}
to {
-webkit-mask-image: linear-gradient(to right, black 100%, black 100%, transparent 100%);
mask-image: linear-gradient(to right, black 100%, black 100%, transparent 100%);
}
}
.reveal {
animation: wipe-reveal 2s ease forwards;
}
/* Circular expand */
@keyframes expand-circle {
from {
-webkit-mask-image: radial-gradient(circle, black 0%, transparent 0%);
mask-image: radial-gradient(circle, black 0%, transparent 0%);
}
to {
-webkit-mask-image: radial-gradient(circle, black 100%, transparent 100%);
mask-image: radial-gradient(circle, black 100%, transparent 100%);
}
}
/* Breathing effect */
@keyframes breathe {
0%, 100% {
-webkit-mask-image: radial-gradient(circle, black 50%, transparent 60%);
mask-image: radial-gradient(circle, black 50%, transparent 60%);
}
50% {
-webkit-mask-image: radial-gradient(circle, black 60%, transparent 70%);
mask-image: radial-gradient(circle, black 60%, transparent 70%);
}
}
/* Hover reveal */
.hover-reveal {
-webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 0%);
mask-image: linear-gradient(to bottom, black 0%, transparent 0%);
transition: mask-image 0.6s ease;
}
.hover-reveal:hover {
-webkit-mask-image: linear-gradient(to bottom, black 100%, transparent 100%);
mask-image: linear-gradient(to bottom, black 100%, transparent 100%);
}
/* Animated pattern */
@keyframes scroll-pattern {
from {
-webkit-mask-position: 0 0;
mask-position: 0 0;
}
to {
-webkit-mask-position: 50px 50px;
mask-position: 50px 50px;
}
}
.scrolling-stripes {
-webkit-mask-image: repeating-linear-gradient(45deg, black 0, black 20px, transparent 20px, transparent 40px);
mask-image: repeating-linear-gradient(45deg, black 0, black 20px, transparent 20px, transparent 40px);
animation: scroll-pattern 2s linear infinite;
}
Performance: Animating mask-position or mask-size performs better than animating mask-image with different gradient values.
Masks vs Clip-Path vs Opacity
Choose the right technique for your transparency needs: masks for gradual fades, clip-path for hard edges, opacity for uniform transparency.
/* clip-path - Hard-edged clipping */
.clipped {
clip-path: circle(50%);
}
/* ✓ Hard, geometric shapes
✓ Perfect for polygons, circles, basic shapes
✓ No gradual transparency
✓ Best performance */
/* mask-image - Gradual transparency */
.masked {
-webkit-mask-image: radial-gradient(circle, black 40%, transparent 60%);
mask-image: radial-gradient(circle, black 40%, transparent 60%);
}
/* ✓ Gradual fades and soft edges
✓ Pattern overlays
✓ Complex transparency with SVG
✓ More resource-intensive */
/* opacity - Uniform transparency */
.faded {
opacity: 0.5;
}
/* ✓ Entire element becomes transparent
✓ Affects all children
✓ Simple, performant
✗ No partial transparency control */
/* Combining techniques */
.combined {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
-webkit-mask-image: linear-gradient(to bottom, black, transparent);
mask-image: linear-gradient(to bottom, black, transparent);
opacity: 0.9;
}
/* Clip to shape, apply gradient fade, reduce overall opacity */
/* When to use each */
/* Use clip-path for: */
.avatar { clip-path: circle(50%); } /* Profile pictures */
.diamond { clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); } /* Geometric shapes */
/* Use mask-image for: */
.text-fade { mask-image: linear-gradient(black 80%, transparent); } /* Fade effects */
.vignette { mask-image: radial-gradient(circle, black 50%, transparent 80%); } /* Soft edges */
/* Use opacity for: */
.disabled { opacity: 0.5; } /* Disabled states */
.tooltip { opacity: 0; transition: opacity 0.3s; } /* Show/hide transitions */
Decision Guide: Need hard geometric edges? Use clip-path. Need gradual fading or patterns? Use mask-image. Need uniform transparency? Use opacity.
Key Takeaways
Black = visible, White = transparent: Mask images use luminance for transparency
Vendor prefix required: Always include -webkit-mask-image alongside mask-image
Gradient masks: Use linear-gradient or radial-gradient for fade effects and vignettes
Pattern masks: repeating-linear-gradient creates stripes, dots, and geometric patterns
SVG masks: Use url() with SVG files for complex shapes and icon-based masks
mask-size: Control pattern density; works like background-size
mask-position: Position masks; works like background-position
mask-repeat: Control tiling; works like background-repeat
Layered masks: Combine multiple mask-images with mask-composite
Animatable: Animate mask-position and mask-size for smooth effects
vs clip-path: Masks support gradual transparency; clip-path only hard edges
vs opacity: Masks control specific areas; opacity affects entire element uniformly
Masks are more resource-intensive than clip-path or opacity; use strategically