CSS Masking
Control element visibility with image-based masks and shape masks using mask-image, mask-size, and mask-composite for creative effects.
Overview
Key Points
- •Masking is alpha-based: black (opaque) shows the element, transparent hides it
- •mask-image accepts gradient functions, url(), and SVG references
- •Multiple mask layers work like multiple backgrounds, separated by commas
- •mask-composite: add, subtract, intersect, and exclude combine layers
- •mask-mode: alpha uses the mask image alpha channel; luminance uses brightness
- •-webkit-mask is required as a prefix in some Safari versions
- •Mask properties mirror background shorthand properties in syntax
- •mask: shorthand combines mask-image, mask-position, mask-size, mask-repeat in one declaration
Examples
Gradient fade-out effects
/* Fade to transparent at the bottom */
.text-fade {
mask-image: linear-gradient(to bottom, black 50%, transparent);
/* Shorthand: mask: linear-gradient(to bottom, black 50%, transparent); */
}
/* Fade on all four sides (vignette) */
.vignette {
mask-image: radial-gradient(
ellipse 80% 80% at center,
black 60%,
transparent 100%
);
}
/* Horizontal fade for a scrollable list preview */
.preview-list {
mask-image: linear-gradient(
to right,
transparent,
black 10%,
black 90%,
transparent
);
}These effects are common for "read more" text truncation, scroll hint indicators, and hero image overlays.
Text as a mask (text-clip effect)
/* Image showing through text */
.text-clip {
background-image: linear-gradient(135deg, #6366f1, #ec4899, #f59e0b);
color: transparent;
-webkit-background-clip: text;
background-clip: text;
}
/* Alternative: mask-based text shape (for non-text content) */
.icon-badge {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
mask-image: url(icon.svg);
mask-size: 100% 100%;
width: 48px;
height: 48px;
}Multiple mask layers
.multi-mask {
mask-image:
linear-gradient(to right, transparent 0%, black 20%), /* fade in left */
linear-gradient(to left, transparent 0%, black 20%), /* fade in right */
linear-gradient(to bottom, black 80%, transparent); /* fade out bottom */
mask-composite: intersect, intersect;
}
/* Punch a hole in an element with mask-composite */
.donut {
mask-image:
radial-gradient(circle 60px, transparent 100%), /* hole */
linear-gradient(black, black); /* full visible */
mask-composite: exclude;
}mask-composite controls how stacked mask layers interact, similar to blend modes for images.
Reveal animation using animated mask
@keyframes reveal-wipe {
from { mask-size: 0% 100%; }
to { mask-size: 100% 100%; }
}
.wipe-reveal {
mask-image: linear-gradient(to right, black, black);
mask-size: 0% 100%;
mask-repeat: no-repeat;
animation: reveal-wipe 1.2s ease forwards;
}
/* Circle expand reveal */
@keyframes circle-reveal {
from { mask-size: 0%; }
to { mask-size: 200%; }
}
.circle-reveal {
mask-image: radial-gradient(circle at center, black 50%, transparent 50%);
mask-size: 0%;
mask-repeat: no-repeat;
mask-position: center;
animation: circle-reveal 0.8s ease-out forwards;
}Common Mistakes
- Forgetting -webkit-mask for Safari compatibility (can combine: mask: ...; -webkit-mask: ...)
- Using mask-image with a color that is not pure black or transparent (off-white masks partially hide the element)
- Confusing clip-path (sharp geometric clip) with mask-image (can have soft edges)
- Setting mask-size without specifying mask-repeat: no-repeat causing the mask to tile unexpectedly
Note
Use mask-image: linear-gradient(to bottom, black 70%, transparent) as a "read more" fade effect on truncated text. It is more elegant than a hard clip and does not require JS to detect overflow.
Exercises
Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.
Completed: 0 / 3 exercises
Knowledge Check
Question 1 of 3