Command Palette

Search for a command to run...

Hectal
PHASE 10Advanced ~29 min· topic 4 of 6

Topic 10.4

Filters, Blend Modes and Masks

In one line

filter applies photo effects such as blur, grayscale and drop shadows to an element, backdrop-filter applies them to what's behind it, mix-blend-mode mixes its colours with the content underneath, and clip-path and mask hide parts of it with a shape or an image.

Think of it like this

Things you put in front of a camera. A filter is a coloured or frosted lens on the camera: everything you photograph through it looks blurred or black-and-white. Frosted glass in a bathroom window is a backdrop filter: the glass itself is clear-ish, but whatever is behind it looks blurry. Blending is like painting with see-through watercolours, where the colour underneath changes the colour you see. Clipping is cutting a photo into a circle with scissors, and a mask is a stencil you can spray through, where the paint fades at soft edges.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Filter function
One effect like blur() or grayscale(), applied to the element's painted pixels.
Backdrop
Whatever is painted behind an element: the page, images, other elements.
Blend mode
A rule for mixing two colours on top of each other, like multiply or screen.
Alpha
How opaque a pixel is, from fully transparent (0) to fully solid (1).
Clip path
A shape outside of which nothing of the element is drawn, with hard edges.
Mask
An image or gradient whose transparency decides how much of the element shows, so edges can be soft.
Isolation
Making a group, so blend modes inside it only mix with things in the group.
Stacking context
A group of layers painted together, so children can't be layered between outside elements (Topic 6.3).

Step by step

01Apply a filter

One property, a list of functions. Grey the image out and lower its brightness, for example to show a sold-out product. Hover removes the filter with a transition (filter functions interpolate when the lists match).

style.csswhole filecss
.product.sold-out img {
  filter: grayscale(1) brightness(0.8);
  transition: filter 0.3s;
}
.product.sold-out:hover img {
  filter: grayscale(0) brightness(1);
}

02Shadow the shape, not the box

An SVG star with a transparent background gets a square shadow from box-shadow. drop-shadow() follows its points.

style.csswhole filecss
.icon {
  filter: drop-shadow(2px 4px 4px rgb(0 0 0 / 0.4));
}

03Frost the glass

A semi-transparent panel over a busy background, with backdrop-filter. The fallback background stays readable in browsers that don't support it, so it degrades gracefully.

style.csswhole filecss
.glass {
  background: rgb(255 255 255 / 0.55); /* readable even without blur */
  backdrop-filter: blur(10px) saturate(1.4);
}

04Blend text into an image

Big white heading text with mix-blend-mode: difference over a photo shows the photo's negative inside the letters. Put isolation: isolate on the hero so the text doesn't blend with the rest of the page.

style.csswhole filecss
.hero { isolation: isolate; }
.hero h1 {
  color: white;
  mix-blend-mode: difference;
}

05Cut a shape, then fade an edge

clip-path cuts with scissors; mask-image uses a stencil with soft edges. Both leave the layout box alone.

style.csswhole filecss
.avatar { clip-path: circle(50%); }
.excerpt {
  max-height: 6em;
  overflow: hidden;
  mask-image: linear-gradient(black 60%, transparent);
}
Cut a shape, then fade an edgediagram
Rendering diagram…

Try it yourself

  1. 1

    Swap the filter order

    In the first example, give one picture filter: sepia(1) hue-rotate(180deg) and another filter: hue-rotate(180deg) sepia(1). Predict which one ends up brown (the second: sepia is applied last).

  2. 2

    Try every blend mode

    In the third example, cycle mix-blend-mode through multiply, screen, overlay, exclusion and luminosity. Then remove isolation: isolate from .hero and set body { background: black; }: predict whether the heading changes (it can, because without isolation it may blend with more than the hero).

  3. 3

    Make a hexagon and test the click

    In the fourth example, change .tri to a hexagon: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%). Then change the JavaScript to test a point in its top-left corner. Predict the element it finds before you run.

Code & diagrams

The filter functions New tab

One small "photo" (a sun over hills, drawn with gradients) through eight lenses. The computed `filter` keeps your list in order.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

none
grayscale(1)
contrast(2) saturate(2)
drop-shadow follows the shape, box-shadow follows the box New tab

The image file is a transparent square with a star in it. `box-shadow` only knows the square; `drop-shadow()` uses the star's real pixels.

Preview

Press Run to see the page.

Console

Nothing logged yet.
Frosted glass and blend modes New tab

Remove `backdrop-filter` and the stripes show sharply through the panel. Change `difference` to `multiply`, `screen` or `overlay` and compare: white with `multiply` disappears entirely.

Preview

Press Run to see the page.

Console

Nothing logged yet.
clip-path shapes, masks and clicks New tab

The clipped-away corner is not part of the element any more for clicks: `elementFromPoint` (what a click there would hit) finds the `.row` behind it. The layout box is unchanged. `circle(40%)` keeps its default centre (`at 50% 50%`), so the computed value leaves it out.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

clip-path: circle(40%)
click at the centre hits: shape circle
click at the corner hits: row
layout width is still 80

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

backdrop-filter on an opaque background

Write .panel { background: white; backdrop-filter: blur(10px); }.

terminal
$ the page shows
── what you'll see ──
A plain white panel. No blur is visible.

Break #2

A filter on a parent breaks a fixed header

Add filter: grayscale(1) to <main> for a "grey mode", where <main> contains a position: fixed header.

terminal
$ the page shows
── what you'll see ──
The header now scrolls away with the page and sits at the top of main instead of the viewport.

Break #3

A clip-path that eats the focus ring

Clip a <button> with clip-path: circle(50%) and tab to it with the keyboard.

terminal
$ the page shows
── what you'll see ──
No focus outline is visible, so keyboard users can't tell the button is focused.

Myth vs fact

Myth

filter: drop-shadow() and box-shadow are the same thing.

Fact

box-shadow shadows the box (and supports spread and inset). drop-shadow() shadows the painted pixels, so it follows transparent images and clipped shapes, but has no spread or inset.

Myth

Clipped-away parts of an element can still be clicked.

Fact

Hit-testing respects clip-path: clicks on the hidden part go to whatever is underneath. Masks are different: the spec doesn't require a mask to change hit-testing, so a fully masked, invisible area may still receive clicks. Don't rely on a mask to block clicks.

Myth

opacity: 0.5 and filter: opacity(0.5) are identical.

Fact

They look the same, but filter: opacity() sits in the filter list (so its order with other filters matters) and may be slower; opacity is the cheap, compositor-friendly one to animate.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The painting order is: the element paints, then filter, then clip-path and mask, then opacity, and finally the result is blended with the backdrop using mix-blend-mode. So a drop-shadow() is clipped by a clip-path on the same element; to keep the shadow, put the clip on a child and the filter on the parent.

  • ▸

    Blur cost grows with the blur radius and the area covered. Large backdrop-filter regions (a sticky header over a scrolling page) are re-filtered every frame and are a common cause of scroll jank on mid-range phones; test on real devices and keep radii small.

  • ▸

    filter, backdrop-filter, clip-path and mask interpolate when their function lists match, so they can be transitioned and animated. clip-path polygons interpolate point by point only when both shapes have the same number of points. They usually need repaint work each frame, not just compositing, though browsers can accelerate some filters on the GPU.

  • ▸

    In forced-colors mode (Windows High Contrast), browsers replace your colours with the user's system colours and drop shadows, so effects built from colour and shadow can vanish. Never put meaning only in a filtered or blended effect: make sure text stays readable without it (see Topic 11.7, Accessible CSS).

Remember this

  1. 1

    filter takes one or more filter functions and applies them to the element and everything inside it, after it's painted: blur(4px) (softens; the length is how far the blur spreads), brightness(1.2) (1 is unchanged), contrast(1.5), grayscale(1) (1 or 100% is fully grey), sepia(1) (old-photo brown), saturate(2) (more vivid colour), hue-rotate(90deg) (shifts every colour around the colour wheel), invert(1) (a photo negative), opacity(0.5) and drop-shadow(x y blur colour). Several functions are applied in order, left to right, so grayscale(1) sepia(1) differs from sepia(1) grayscale(1). filter: url(#id) points to an SVG filter for effects CSS can't express.

  2. 2

    drop-shadow() differs from box-shadow: box-shadow draws a shadow of the element's rectangle (rounded by border-radius), while drop-shadow() follows the actual shape of the painted pixels, including transparent parts of a PNG or SVG icon. It has no spread value and no inset, and it's usually slower, because the browser must blur the real pixel shape.

  3. 3

    backdrop-filter (Baseline 2024) applies the same functions to the content behind the element, inside the element's border box, giving the "frosted glass" look: background: rgb(255 255 255 / 0.4); backdrop-filter: blur(10px);. The element's own background must be at least partly transparent, or you can't see the effect. It's one of the most expensive effects in CSS, because the browser must re-blur whatever is behind the element whenever that changes (for example, every frame while scrolling).

  4. 4

    mix-blend-mode decides how an element's colours mix with whatever is painted below it. normal simply covers it. multiply darkens (like overlapping inks: white disappears), screen lightens (black disappears), overlay boosts contrast, difference subtracts colours (white text over a photo becomes its negative), and darken, lighten, color-dodge, color-burn, hard-light, soft-light, exclusion, hue, saturation, color and luminosity cover the rest. background-blend-mode blends an element's own background layers (a colour with a background image) instead. isolation: isolate on a parent creates a group, so children blend only with each other and the parent's background, not the whole page.

  5. 5

    clip-path hides everything outside a shape, with hard edges: inset(10px round 12px) (a rectangle shrunk inwards, with rounded corners), circle(40%) or circle(50px at 30% 40%), ellipse(60% 40%), polygon(50% 0, 100% 100%, 0 100%) (a triangle from points), path("...") (an SVG path) or url(#clip). The hidden part is not painted and can't be clicked: clicks there go to whatever is behind. The layout box doesn't change; clip-path, like transform, only affects drawing. Shapes with the same number of points can be animated smoothly.

  6. 6

    mask-image (Baseline 2023) is a softer stencil. It takes an image or gradient, and each pixel's alpha (transparency) decides how much of the element shows: opaque means fully visible, transparent means hidden, half-transparent means half visible. mask-image: linear-gradient(black 70%, transparent) fades the bottom of a long text out. Masks have the same helper properties as backgrounds (mask-size, mask-repeat, mask-position), and mask-mode: luminance uses brightness instead of alpha. Like opacity < 1, a filter, a mask, a clip-path or a non-normal mix-blend-mode creates a stacking context (Topic 6.3); filter and backdrop-filter also become the containing block for fixed descendants.

Explain it without notes

01

What does filter do, and why does the order of filter functions matter?

02

When would you use drop-shadow() instead of box-shadow?

03

How does backdrop-filter differ from filter, and what does it need to be visible?

04

What is mix-blend-mode, and what problem does isolation: isolate solve?

05

Compare clip-path and mask-image.

Practice

01

Make every image inside .gallery grey and slightly dark, and show its real colours when hovered, with a 0.3s transition.

02

Make a .badge cut into a triangle pointing right, using clip-path.

03

Fade out the right-hand edge of a horizontally scrolling .chips row with a mask, so it hints there is more to scroll.

Trade-offs

  • ↔

    Filters and blends give image-editor effects without editing images, but they cost paint and GPU time on every change; prepare effects in the image itself when they never change.

  • ↔

    backdrop-filter looks modern but is expensive and reduces contrast unpredictably over busy content; always keep a semi-opaque background so text stays readable.

  • ↔

    clip-path is cheap and animatable but hard-edged and clips outlines; masks are soft and flexible but don't affect clicks the same way and can be harder to debug.

Done when you can

  • I can combine filter functions and predict the effect of their order.

  • I can choose between box-shadow and drop-shadow().

  • I can build a frosted-glass panel with a readable fallback.

  • I can use mix-blend-mode and contain it with isolation: isolate.

  • I can cut shapes with clip-path and fade edges with mask-image.

  • I know these effects create stacking contexts, and some create containing blocks.