Filters & Blend Modes
Photo apps on your phone can blur, brighten, fade to black and white or tint a picture. CSS can do the same to any element on a web page, live in the browser, without editing the image file. Filters change how an element itself looks, and blend modes decide how an element mixes with whatever is behind it.
In this lesson you will use the filter property, build a frosted-glass panel with backdrop-filter, and mix colours and images with mix-blend-mode and background-blend-mode.
The filter property
filter takes one or more filter functions. Each function changes the rendered pixels of the element, including all its children.
| Function | Effect | Example |
|---|---|---|
blur() | Softens the element | blur(4px) |
brightness() | Lighter or darker; 1 is normal | brightness(1.2) |
contrast() | More or less contrast; 1 is normal | contrast(1.5) |
grayscale() | Removes colour; 1 is fully grey | grayscale(1) |
sepia() | Old-photo brown tone | sepia(0.8) |
saturate() | More or less colour strength | saturate(2) |
hue-rotate() | Shifts every colour around the colour wheel | hue-rotate(90deg) |
invert() | Reverses the colours | invert(1) |
opacity() | Transparency, like the opacity property | opacity(0.5) |
drop-shadow() | A shadow that follows the shape | drop-shadow(0 4px 6px black) |
Most functions also accept percentages, so grayscale(100%) is the same as grayscale(1). Write several functions separated by spaces; they are applied from left to right.
A popular effect is a gallery where photos are grey until you point at them:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Filter gallery</title>
<style>
body { font-family: system-ui, sans-serif; margin: 16px; }
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
}
.gallery figure { margin: 0; }
.gallery img { width: 100%; display: block; border-radius: 8px; }
.gallery figcaption { font-size: 0.85rem; }
.grey { filter: grayscale(1); transition: filter 300ms; }
.grey:hover { filter: grayscale(0); }
.old { filter: sepia(0.9) contrast(1.1); }
.bright { filter: brightness(1.3) saturate(1.6); }
.soft { filter: blur(3px); }
</style>
</head>
<body>
<div class="gallery">
<figure><img class="grey" src="https://course.ethicscomputer.in/assets/samples/landscape-400.svg" alt="Hills and a river at sunrise"><figcaption>grayscale (hover me)</figcaption></figure>
<figure><img class="old" src="https://course.ethicscomputer.in/assets/samples/landscape-400.svg" alt="Hills and a river at sunrise"><figcaption>sepia + contrast</figcaption></figure>
<figure><img class="bright" src="https://course.ethicscomputer.in/assets/samples/landscape-400.svg" alt="Hills and a river at sunrise"><figcaption>brightness + saturate</figcaption></figure>
<figure><img class="soft" src="https://course.ethicscomputer.in/assets/samples/landscape-400.svg" alt="Hills and a river at sunrise"><figcaption>blur</figcaption></figure>
</div>
</body>
</html>The same image file is used four times. Only the CSS differs, so the visitor downloads it once.
drop-shadow() versus box-shadow
You met box-shadow in Borders, Radius & Shadows. It always draws a shadow around the element's box, a rectangle with optional rounded corners. filter: drop-shadow() instead follows the visible shape, so a star icon gets a star-shaped shadow and a PNG or SVG with a transparent background gets a shadow only under the drawn parts.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>drop-shadow vs box-shadow</title>
<style>
body { font-family: system-ui, sans-serif; margin: 24px; display: flex; gap: 48px; }
svg { width: 120px; height: 120px; }
.box-shadow { box-shadow: 6px 6px 8px rgb(0 0 0 / 0.4); }
.drop-shadow { filter: drop-shadow(6px 6px 4px rgb(0 0 0 / 0.4)); }
</style>
</head>
<body>
<figure>
<svg class="box-shadow" viewBox="0 0 100 100" aria-hidden="true">
<polygon points="50,5 61,38 95,38 67,58 78,92 50,72 22,92 33,58 5,38 39,38" fill="#f59e0b"/>
</svg>
<figcaption>box-shadow</figcaption>
</figure>
<figure>
<svg class="drop-shadow" viewBox="0 0 100 100" aria-hidden="true">
<polygon points="50,5 61,38 95,38 67,58 78,92 50,72 22,92 33,58 5,38 39,38" fill="#f59e0b"/>
</svg>
<figcaption>drop-shadow()</figcaption>
</figure>
</body>
</html>drop-shadow() takes an x offset, a y offset, a blur and a colour. Unlike box-shadow, it has no spread value and no inset option.
backdrop-filter: frosted glass
backdrop-filter applies filters to whatever is behind an element, not to the element itself. Combined with a semi-transparent background, it creates the "frosted glass" look used on many app bars and pop-ups.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Frosted glass</title>
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.hero {
min-height: 320px;
display: grid;
place-items: center;
background: url("https://course.ethicscomputer.in/assets/samples/landscape.svg") center / cover, #0f766e;
}
.glass {
max-width: 280px;
padding: 20px;
border: 1px solid rgb(255 255 255 / 0.4);
border-radius: 16px;
background: rgb(255 255 255 / 0.25);
backdrop-filter: blur(10px) saturate(1.4);
color: #0f172a;
}
.glass h1 { margin: 0 0 8px; font-size: 1.4rem; }
</style>
</head>
<body>
<section class="hero">
<div class="glass">
<h1>Munnar Tea Trails</h1>
<p>Two-day guided walks from Kochi, every weekend.</p>
</div>
</section>
</body>
</html>The panel's background is only 25% white, so the image shows through, but the blur makes it soft enough for the text to stay readable. Two things to remember:
- The effect only shows if the element's own background is at least partly transparent.
- Make sure the text is readable even without the blur.
backdrop-filterworks in all current major browsers, but older Safari versions needed the prefixed-webkit-backdrop-filterand older browsers without support simply ignore it, so choose a background colour strong enough on its own.
Blend modes
A blend mode decides how the colours of two layers mix, exactly like the layer modes in Photoshop or GIMP.
mix-blend-modeblends an element with everything behind it on the page.background-blend-modeblends an element's own background layers (images, gradients and the background colour) with each other.
| Mode | Result |
|---|---|
normal | No mixing (the default) |
multiply | Darkens; white disappears |
screen | Lightens; black disappears |
overlay | Increases contrast |
darken / lighten | Keeps the darker or lighter colour of each pixel |
difference | Subtracts colours; white on white becomes black |
color / luminosity | Takes the colour or the brightness from the top layer |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Blend modes</title>
<style>
body { margin: 16px; font-family: system-ui, sans-serif; }
.tinted {
height: 180px;
border-radius: 12px;
background-color: #7c3aed;
background-image: url("https://course.ethicscomputer.in/assets/samples/landscape.svg");
background-size: cover;
background-blend-mode: luminosity;
}
.split {
margin-top: 16px;
padding: 24px;
border-radius: 12px;
background: linear-gradient(90deg, #111827 50%, #f9fafb 50%);
}
.split h2 {
margin: 0;
font-size: 2.5rem;
text-align: center;
color: white;
mix-blend-mode: difference;
}
</style>
</head>
<body>
<div class="tinted" role="img" aria-label="Hills at sunrise, tinted purple"></div>
<div class="split"><h2>Rohtak Robotics</h2></div>
</body>
</html>The first box keeps the brightness of the photo but takes its colour from the purple background colour, giving a one-colour "duotone" look that matches a brand. In the second box, difference makes the white heading turn black over the light half and stay white over the dark half, so it is readable on both.
If a blend affects more than you want, add isolation: isolate to a parent. Blending then stops at that parent instead of mixing with the whole page behind it.
Performance and accessibility
- Large
blur()orbackdrop-filtervalues on big areas take a lot of work to draw and can make scrolling stutter on budget phones. Keep blurred areas small and avoid animating them. - Text on top of images and glass panels must still meet contrast guidelines. Check it in both light and dark themes.
- Do not use
filter: invert(1)as a quick dark mode. It also inverts photos and logos. See Dark Mode & Theming for a better way.
Common mistakes
- Expecting
filterto affect only the background. It affects the element and all its children, including text. Usebackdrop-filteror put the effect on a separate element. - A
backdrop-filterthat does nothing. The element's background must be partly transparent, and there must be something behind it to blur. - Using
box-shadowon icons. It draws a rectangle. Usedrop-shadow()for shaped images. - Blending more than intended.
mix-blend-modemixes with everything behind it; useisolation: isolateto limit it.
Key points
filterapplies effects such asblur(),grayscale(),brightness()anddrop-shadow()to an element and its children.- Functions are separated by spaces and applied from left to right.
drop-shadow()follows the visible shape;box-shadowfollows the box.backdrop-filterblurs or tints what is behind a semi-transparent element, for frosted-glass effects.mix-blend-modeblends an element with the page behind it;background-blend-modeblends its own background layers.- Keep heavy effects small, check text contrast, and never rely on
invert()for dark mode.
Exercise
Create a sale banner for a clothes shop in Lucknow. Use the sample landscape image (landscape.svg from the examples above) as a background image, tint it orange with background-blend-mode: multiply and a background colour, and place a white text panel on top that uses backdrop-filter: blur(6px) with a semi-transparent background. Then add a small "50% OFF" badge with a filter: drop-shadow().
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sale banner</title>
<style>
.banner {
display: grid;
place-items: center;
min-height: 260px;
background: url("https://course.ethicscomputer.in/assets/samples/landscape.svg") center / cover, #f97316;
background-blend-mode: multiply;
}
.panel {
padding: 16px 24px;
border-radius: 12px;
background: rgb(255 255 255 / 0.3);
backdrop-filter: blur(6px);
text-align: center;
}
.badge {
display: inline-block;
padding: 4px 10px;
background: #dc2626;
color: white;
filter: drop-shadow(0 3px 3px rgb(0 0 0 / 0.4));
}
</style>
</head>
<body>
<section class="banner">
<div class="panel">
<h1>Winter Sale in Lucknow</h1>
<span class="badge">50% OFF</span>
</div>
</section>
</body>
</html>multiply darkens the image with the orange background colour, so the white parts turn orange. The panel blurs the tinted image behind it, and the badge gets a shadow that follows its shape.
Quick Quiz
1. What does filter: grayscale(1) do?
grayscale(1) (or 100%) turns everything the element draws into shades of grey.
2. A star-shaped SVG icon needs a shadow that follows the star. What should you use?
drop-shadow() follows the visible pixels, while box-shadow follows the rectangular box.
3. Why might backdrop-filter: blur(10px) show no visible effect?
The backdrop is only visible through a partly transparent background.
4. What is the difference between mix-blend-mode and background-blend-mode?
One mixes an element with its surroundings, the other mixes the background images and colour of a single element.
Learn CSS with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
