14 — Filters, Blend Modes & Masking: Compositing Pipeline
filter applies Photoshop-like effects to an element. backdrop-filter filters the content behind an element (glassmorphism). mix-blend-mode blends an element with its backdrop. All three create stacking contexts — that's the trap.
filter — graphical effects
css
.img { filter: blur(5px); }
.img { filter: brightness(1.5); } /* 0=black, 1=normal, 2=2x bright */
.img { filter: contrast(2); }
.img { filter: grayscale(1); } /* 0=color, 1=gray */
.img { filter: hue-rotate(90deg); } /* theming without re-exporting assets */
.img { filter: invert(1); }
.img { filter: saturate(2); }
.img { filter: sepia(1); }
.img { filter: drop-shadow(4px 4px 10px rgba(0,0,0,0.5)); /* follows the ALPHA SHAPE, not the box */
.img { filter: grayscale(1) blur(2px) brightness(1.2); } /* chained: left to right */
drop-shadow vs box-shadow — shape vs box
css
/* drop-shadow follows the element's alpha shape (PNG transparency, clip-path, SVG). */
/* box-shadow is always the rectangular box. */
.icon-png { filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.5)); } /* shadow follows the icon shape */
.icon-png { box-shadow: 2px 2px 4px rgba(0,0,0,0.5); } /* shadow on the rectangular box */
/* drop-shadow has NO spread (unlike box-shadow): only offset-x offset-y blur color. */
backdrop-filter — glassmorphism
css
.glass {
background: rgba(255, 255, 255, 0.2); /* MUST be translucent — the blur shows THROUGH the background */
-webkit-backdrop-filter: blur(10px); /* Safari needs -webkit- */
backdrop-filter: blur(10px); /* standard */
border: 1px solid rgba(255, 255, 255, 0.3);
}
/* ⚠️ Needs content BEHIND the element to blur — a solid background shows no effect. */
/* ⚠️ Expensive: samples + filters the backdrop each frame. Use on small areas, don't animate. */
Anti-pattern: opaque background hides the blur
css
/* ❌ 80% opaque → only 20% of backdrop shows → blur barely visible. Looks like a solid panel. */
.glass { background: rgba(255, 255, 255, 0.8); backdrop-filter: blur(10px); }
css
/* ✓ 20% opaque → 80% of backdrop shows → blur visible. Plus content behind to blur. */
.glass { background: rgba(255, 255, 255, 0.2); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
Blend Modes
css
/* mix-blend-mode: blends element with the BACKDROP (content behind it, not siblings/children). */
.overlay { mix-blend-mode: multiply; } /* multiply darkens; screen lightens; overlay = contrast */
/* ⚠️ mix-blend-mode creates a stacking context (like opacity<1). */
/* difference: inverts based on backdrop → text against white becomes black, against black becomes white */
.adaptive-text { mix-blend-mode: difference; color: white; } /* guaranteed contrast on any backdrop */
/* background-blend-mode: blends an element's OWN background layers (not the backdrop). */
.box { background: url("texture.png"), linear-gradient(to right, red, blue); background-blend-mode: overlay; }
Masking — mask for soft alpha fades
css
/* mask uses an image's alpha (or luminance) to control visibility — soft edges, gradients. */
/* clip-path can only HARD-clip; mask can SOFT-fade. */
.fade-bottom {
-webkit-mask: linear-gradient(to bottom, black, transparent); /* Safari */
mask: linear-gradient(to bottom, black, transparent); /* standard */
}
/* mask-mode: alpha (default) uses alpha channel; luminance uses brightness (white=visible, black=hidden). */
💡 Tips & Tricks
- Idiom:
drop-shadow(notbox-shadow) for non-rectangular elements — PNG icons, SVGs,clip-path-ed shapes. The shadow follows the alpha shape.box-shadowis always rectangular. - Idiom:
maskwithlinear-gradientfor soft fade-outs —mask: linear-gradient(to bottom, black, transparent)fades to transparent.clip-pathcan only hard-clip. - Idiom:
mix-blend-mode: differencefor guaranteed-contrast text on variable backgrounds — text against white → black, against black → white. - Idiom:
filter: hue-rotate()for theming assets without re-exporting — shift a colored icon's hue to match a theme. Combine withsaturate()/brightness()for fuller control. - Idiom:
backdrop-filtersparingly (expensive) and only on small translucent surfaces with content behind to blur.
⚠️ Edge Cases & Gotchas
filtercreates a stacking context: likeopacity < 1andtransform,filtertraps children's z-index. A filtered parent's children can't escape its context.backdrop-filterneeds a translucent background: opaque (0.8) hides the blur. Use 0.1–0.3. And needs content behind to blur.backdrop-filteris expensive: samples + filters the backdrop each frame. Don't animate it, don't use on large areas.mix-blend-modeblends with the backdrop, not siblings/children: it blends with content behind the element (ancestors, earlier siblings in the same context).mix-blend-mode: differenceagainst mid-gray (128,128,128): inverts to the same gray → text disappears on mid-gray backdrops.-webkit-maskvsmask: older Safari only supports-webkit-maskwith limited syntax. Include both for cross-browser; test in Safari.drop-shadowhas no spread: onlyoffset-x offset-y blur color.box-shadowhas spread;drop-shadowdoesn't.
🧠 Spot the Bug
css
.glass {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
Answer
The background is 80% opaque → only 20% of the backdrop shows through → the blur is barely visible. The card looks like a solid white panel, not frosted glass. Fix: background: rgba(255, 255, 255, 0.2) (translucent) so the blurred backdrop is visible. Also ensure there's colorful/textured content behind the card to blur — backdrop-filter blurs what shows through the background, and a solid backdrop shows no effect. Include -webkit-backdrop-filter for Safari.