CSS Glassmorphism in 2025: the right way to implement it
Most tutorials you find online were written in 2021. Here is what has changed — and what you have been doing wrong.
Glassmorphism exploded in 2021 thanks to a Figma tutorial and Apple’s macOS Big Sur redesign. Four years later, backdrop-filter has reached 96 % global support, but the articles ranking for the query are still the same — outdated, performance-blind, and accessibility-deaf. This guide fills the gap.
We will cover the correct CSS property stack, how to guarantee legible text on any background, why your glass card destroys frame rate on Android, and how to write a single progressive implementation that degrades gracefully in every browser.
What glassmorphism actually is (and is not)
Glassmorphism is a UI style that simulates frosted glass: a translucent surface that blurs the content behind it. The effect depends on three visual properties working together:
- Background blur — the defining characteristic, achieved with
backdrop-filter: blur() - Translucent fill — a semi-transparent background color using
rgba()orcolor-mix() - Subtle border — a light inset border to suggest depth and catch edge light
It is not a simple box-shadow effect, and it is not the same as a frosted background image. The blur must be applied to the content behind the element, which is what makes backdrop-filter — not filter — the correct property.
The common mistake in 2021 tutorials was to add filter: blur() to the card itself, which blurs the card’s own content. That is the opposite of what you want.
The correct property stack in 2025
Here is the minimal, correct implementation:
.glass-card {
/* 1. The blur — most important property */
backdrop-filter: blur(12px) saturate(180%);
-webkit-backdrop-filter: blur(12px) saturate(180%);
/* 2. Translucent fill */
background: rgba(255, 255, 255, 0.12);
/* 3. Depth border */
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
/* 4. Shadow for lift */
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
}
The -webkit- prefix is still required for Safari, which ships its own implementation. In 2025, omitting it means your card looks broken for roughly 20 % of mobile traffic.
The saturate(180%) function on backdrop-filter is not strictly necessary but it makes the blurred background appear more vivid, which increases perceived depth. It is the same trick macOS uses for its panel blur.
Background alpha and blur radius
There is an inverse relationship between blur radius and background alpha. The more opaque your fill, the less blur you perceive. A useful starting range:
- Heavy blur (20–30 px) + low alpha (0.05–0.12) → maximum frosted effect
- Medium blur (10–16 px) + medium alpha (0.12–0.25) → standard card
- Light blur (4–8 px) + high alpha (0.3–0.5) → subtle hint of glass
Values outside these ranges either make the glass look like a solid card or create an unreadable smear.
WCAG contrast: the silent accessibility failure
This is where most glassmorphism implementations fail silently. Because the background is a blur of unpredictable content, you cannot know the effective contrast ratio at design time. The text could be sitting over a dark area (fine) or a near-white area (invisible).
WCAG 2.1 Level AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18 pt / 14 pt bold). Most white-text-on-glass implementations fail this threshold when the background content is light.
The three solutions, in order of preference
1. Text shadow / subtle background on text
.glass-card p {
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
Fast, no extra elements, preserves the glass aesthetic. Best for short labels and headings.
2. Higher background alpha in the text area
.glass-card .text-area {
background: rgba(0, 0, 0, 0.35);
padding: 12px 16px;
border-radius: 8px;
}
Creates a darker zone specifically for the text. Works well for cards with a clear “content strip”.
3. Control the background behind the card
If you control the background (a gradient, an image you own), ensure the area behind the glass card never exceeds a certain lightness. This is the cleanest solution architecturally but requires design-level control.
What you should not do is rely on the blur making text readable. It does not — a 12 px blur of a white area is still a near-white area.
Performance: why your glass card destroys frame rate on mobile
backdrop-filter is one of the most GPU-intensive CSS properties. Here is what happens at render time:
- The browser must composite the element into its own layer
- For every frame, it copies the pixels behind the element
- It applies the blur kernel to that copy (expensive, especially at high radius)
- It composites the result back
On a mid-range Android phone with a complex background, a single glass card running at 12 px blur can drop frame rate from 60 fps to 40 fps. Two cards can reach 25 fps. This is not a hypothetical — test it with Chrome DevTools Performance tab.
Performance rules for glassmorphism
- Limit blur radius to 16 px in most cases. 20–30 px is a luxury for desktop-only components
- Avoid animating backdrop-filter. If you need an entrance animation, animate
opacityortransforminstead, and apply the backdrop-filter from the start - Do not stack multiple glass layers on the same z-axis. Each layer multiplies the blur cost
- Add
will-change: transformto force GPU compositing upfront and prevent layout thrashing during scroll - Use
contain: layout style painton the glass element to limit reflow scope
.glass-card {
backdrop-filter: blur(12px) saturate(180%);
-webkit-backdrop-filter: blur(12px) saturate(180%);
will-change: transform;
contain: layout style paint;
}
The reduced-motion consideration
Users who have enabled “Reduce Motion” in their OS settings have often done so because they are sensitive to visual effects — including the shimmering quality that glass can produce when the background scrolls. Respect the preference:
@media (prefers-reduced-motion: reduce) {
.glass-card {
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: rgba(255, 255, 255, 0.85);
}
}Progressive fallback: one implementation, every browser
Despite 96 % global support, there are still edge cases: older Chromium versions in enterprise environments, some WebView implementations, and Firefox with GPU acceleration disabled. A solid implementation handles all of them.
/* Base fallback — always applied first */
.glass-card {
background: rgba(30, 30, 30, 0.85); /* opaque fallback */
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.24);
}
/* Enhancement — only if backdrop-filter is supported */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.glass-card {
background: rgba(255, 255, 255, 0.10);
backdrop-filter: blur(12px) saturate(180%);
-webkit-backdrop-filter: blur(12px) saturate(180%);
}
}
/* Reduced motion override */
@media (prefers-reduced-motion: reduce) {
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
.glass-card {
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: rgba(30, 30, 30, 0.88);
}
}
}
The fallback uses a nearly-opaque background — the card still looks intentional, not broken. The @supports block upgrades it to full glass only where the browser can handle it.
This pattern — opaque base, @supports enhancement, prefers-reduced-motion override — is the correct architecture. It is the same pattern used by the iOS system UI in its CSS implementations.
Dark mode glassmorphism
Light-on-dark glass and dark-on-light glass require different parameter sets. The “standard” tutorial values (white fill, white border) work on dark backgrounds only.
/* Dark theme glass card */
.glass-card {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.15);
backdrop-filter: blur(12px) saturate(180%);
-webkit-backdrop-filter: blur(12px) saturate(180%);
}
/* Light theme glass card */
@media (prefers-color-scheme: light) {
.glass-card {
background: rgba(255, 255, 255, 0.55);
border: 1px solid rgba(255, 255, 255, 0.8);
backdrop-filter: blur(16px) saturate(140%);
-webkit-backdrop-filter: blur(16px) saturate(140%);
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
}
}
For light themes, you need a much higher alpha (0.5+) because the background is already light — the contrast between card and background is lower. Also reduce saturate() slightly to avoid over-saturating the background in bright environments.
When not to use glassmorphism
Being honest about a technique’s limitations is part of using it correctly. Avoid glassmorphism in these situations:
- Data-dense interfaces — tables, code editors, spreadsheets. The blur is distracting and the text legibility tradeoffs are not worth it
- Content over user-generated images — you cannot predict or control the background content, making reliable contrast impossible
- Low-performance target devices — if your audience is primarily on budget Android phones or older tablets, the performance cost is too high
- Interactive overlays requiring fast open/close — modals and dropdowns that animate frequently. Each open/close triggers the full backdrop-filter compositing pipeline
Glassmorphism shines on hero sections, landing pages, settings panels, and UI components over a controlled gradient or image. Use it there, not everywhere.
Try the interactive generator
If reading through the parameters feels abstract, use the PixCode glassmorphism tool to preview changes in real time. It exposes all the values covered in this article — blur radius, alpha, saturation, border opacity, border radius — and lets you export the final CSS with the @supports fallback included.
CSS Glassmorphism in 2025: browser support, performance, accessibility
CSS glassmorphism relies on the backdrop-filter property, which reached full cross-browser support (Chrome, Firefox, Safari, Edge) in 2023. As of 2025, global browser support stands at approximately 96 %, making it safe for production use provided you include the -webkit- prefix for Safari and a solid @supports fallback for the remaining 4 %.
The technique was popularized in 2021 but most documentation predates the widespread availability of backdrop-filter in Firefox, which shipped support in version 103 (2022). Post-Firefox-support, the correct implementation no longer requires JavaScript polyfills or SVG filter workarounds.
From a performance perspective, backdrop-filter forces GPU compositing on the element, which is expensive. The blur kernel is evaluated per-frame, per-pixel, at a cost proportional to blur radius squared. For responsive layouts, it is common practice to reduce the blur radius on smaller viewports using media queries.
Frequently asked questions
What is the difference between backdrop-filter and filter in CSS?+
backdrop-filter applies visual effects (like blur or color adjustments) to the area behind an element, without affecting the element’s own content. filter applies effects to the element itself — including all its children. For glassmorphism, you always want backdrop-filter: using filter: blur() on the card blurs your card’s text, which is the opposite of the intended effect.Does Firefox support backdrop-filter in 2025?+
backdrop-filter support in version 103, released in July 2022. As of 2025, it is fully supported without flags in all major browsers: Chrome 76+, Firefox 103+, Safari 9+ (with -webkit- prefix), and Edge 17+. You still need the -webkit-backdrop-filter prefix for Safari to ensure support across all Safari versions on iOS and macOS.Why does my glass card look bad on mobile?+
How do I make glassmorphism accessible?+
prefers-reduced-motion — some users are sensitive to the shimmering effect of glass over moving backgrounds, and should receive a solid fallback.What blur radius should I use for glassmorphism?+
How do I write a fallback for browsers that do not support backdrop-filter?+
@supports at-rule with a progressive enhancement pattern. Define a solid, nearly-opaque background as the base style — the card still looks intentional, just without the blur. Then inside @supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)), override with the translucent background and the blur filter. This way, unsupported browsers see a clean solid card, while supporting browsers see the full glass effect.