The glassmorphism CSS effect — that frosted-glass look that blurs whatever sits behind it — has become a staple of modern interface design. The trick isn't one magic property; it's the interplay of a translucent background colour, a blur applied through backdrop-filter, a thin border and a soft shadow working together. In this guide we'll build the effect from scratch with both performance and accessibility in mind.
What glassmorphism is and which layers make it up
When you look at a real glass panel you perceive four things at once: the blurred image behind it, the faint tint of the glass, the glint along its edge, and the sense that the surface is floating. In CSS we mimic these with the following layers:
- Blur:
backdrop-filter: blur(...)blurs the pixels behind the element. - Translucency: a low-opacity fill colour via
rgba()orhsl(... / 0.x). - Edge: a 1px semi-transparent white
borderimitates the light catching the rim. - Depth: a wide, soft
box-shadowgives the floating sensation.
One crucial point: the effect is only visible if there's something behind the panel to blur. On a flat, single-colour background glassmorphism disappears; you need a colourful gradient, a photo or blob shapes.
A basic glassmorphism CSS card
At its simplest, a glass card looks like this. We colour the background first, then build the card:
body {
min-height: 100vh;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
display: grid;
place-items: center;
}
.glass {
background: rgba(255, 255, 255, 0.12);
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.25);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
padding: 2rem;
color: #fff;
}
The -webkit-backdrop-filter line isn't there for nothing: Safari supported only the prefixed version for a long time, and on mobile Safari it's still wise to play it safe. Always write the prefixed line before the standard one.
Fine-tuning backdrop-filter
backdrop-filter doesn't only take blur(); you can chain several filters separated by spaces. Boosting saturation is a great way to make the glass feel more vivid:
.glass {
backdrop-filter: blur(12px) saturate(160%);
-webkit-backdrop-filter: blur(12px) saturate(160%);
}
A few practical pointers:
- Blur amount: 8–16px is ideal for most cards. Above 30px it both slows down and loses the "glass" feel.
- Fill opacity: 0.10–0.20 on a light theme, 0.05–0.10 on a dark theme tends to stay balanced.
- Saturation:
saturate(150%–180%)makes the colours behind pop, approximating how real glass refracts light.
Making the edge glint realistic
A flat single-colour border looks a little artificial. In real glass the light comes from above, so the top edge is brighter than the bottom. You can mimic this with a gradient border instead of a solid one:
.glass {
border: 1px solid transparent;
background:
linear-gradient(rgba(255,255,255,0.12), rgba(255,255,255,0.12)) padding-box,
linear-gradient(135deg, rgba(255,255,255,0.6), rgba(255,255,255,0.1)) border-box;
}
Here we use a two-layer background: the first gradient paints the fill via padding-box, the second paints the border via border-box. The edge then fades from bright to dim corner to corner.
Accessibility and readability
The biggest trap with glassmorphism is contrast. Text over a translucent surface can become unreadable depending on the colour behind it. A few safeguards:
- Aim for at least a 4.5:1 contrast ratio between text and its background (WCAG AA, normal text).
- If you're over a highly variable background, add a subtle
text-shadowto the text or nudge the panel's opacity up. - Double safeguard: if
backdrop-filterisn't supported, give a slightly more opaque fallback background so the panel doesn't stay fully transparent and swallow the text.
.glass {
background: rgba(30, 30, 50, 0.6); /* fallback: more opaque */
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.glass {
background: rgba(255, 255, 255, 0.12); /* glass: more transparent */
backdrop-filter: blur(12px) saturate(160%);
-webkit-backdrop-filter: blur(12px) saturate(160%);
}
}
Thanks to the @supports query, the browser uses the transparent glass look when it supports backdrop-filter and the readable opaque fallback when it doesn't. This is a textbook example of progressive enhancement.
Performance: where to be careful
backdrop-filter isn't a cheap effect; the browser has to re-blur the region behind it on every frame. Watch out for:
- Limit the count: use a handful of glass panels rather than dozens on the same screen. Applying blur to every row of a long list slows things down noticeably on mobile.
- Avoid animating it: animations that change the
backdrop-filtervalue every frame are expensive; move the panel withtransformoropacityinstead. - Reduce motion: consider
prefers-reduced-motionand low-powered devices; if needed, serve a simple opaque panel outside@supports.
Frequently Asked Questions
Does backdrop-filter work in all browsers?
It's supported in current Chrome, Edge, Firefox and Safari; Safari required the -webkit- prefix for a long time, so adding the prefixed line is still a good habit. For older browsers, always use the @supports fallback above.
What's the difference between backdrop-filter and filter?
filter blurs the element itself (its content included); backdrop-filter blurs the pixels behind the element and leaves the content sharp. For the glass effect you need the latter.
The effect doesn't show up — why?
The two most common causes: there's no content-rich background behind the panel to blur (it's invisible over a flat colour), or the panel's fill is fully opaque and covers the blurred layer. Use a colourful gradient and lower the fill opacity.
Want a modern glass touch on your interface? I can design and code performant, accessible glassmorphism components that match your brand — get in touch and let's bring your idea to life together.