Apple Glassmorphism CSS: Recreate iOS 26 Liquid Glass Effects
Apple Called It Liquid Glass. Your Blur Filter Is Not That.
Search for Apple glassmorphism CSS and you will find hundreds of demos titled "Liquid Glass." Most of them are a blurred rectangle with a white border. That is glassmorphism, the 2021 recipe. It is not what Apple shipped.
Apple's own description is more specific. In WWDC25 session 219, Liquid Glass is a dynamic material that uses lensing: it dynamically bends and concentrates light instead of just scattering it. It also adapts to what sits behind it, adjusting tint, shadow and dynamic range for legibility. A blur filter does none of that.
The good news is that you can get surprisingly close in CSS, and you can do it responsibly. You need three layers, an honest fallback plan, and accessibility rules written before the first pixel is styled.
Apple glassmorphism in CSS is a stack: frosted base, specular edges, optional refraction, and a fallback for every user the stack cannot reach. Here is how to build each layer.
Section 1: What Liquid Glass Actually Is
Before writing CSS, get the vocabulary right. It decides what you can and cannot copy.
Lensing, adaptive tint and shadows
According to the WWDC25 session, each layer of the material continuously adapts based on what is behind it. Larger glass reads as a thicker material, with deeper shadows and more pronounced lensing and refraction. Small elements can flip between light and dark appearances, while large surfaces such as menus and sidebars adapt without flipping.
Regular vs Clear
Apple defines two variants. Regular is the adaptive default. Clear is permanently transparent and needs a dimming layer behind it. Apple says not to mix them, and to use Clear only when the content below is media-rich, tolerates dimming, and the content above the glass is bold and bright.
On the web, treat Regular as your default token set and Clear as a rare, opt-in variant.
Even Apple added an opacity toggle
iOS 26.1 added a Liquid Glass setting under Display & Brightness with Clear and Tinted options. Tinted raises opacity and contrast. Reporting from CNET and BGR describes it as a response to legibility complaints. The lesson for web teams is blunt: if Apple needed an escape hatch, you do too.
Glassmorphism vs Liquid Glass
| Glassmorphism (2021) | Liquid Glass (Apple) | |
|---|---|---|
| Nature | Static visual recipe | Rendering model |
| Core technique | Blur, translucency, border | Lensing, reflection, adaptive tint |
| Reacts to content behind | Only through the blur | Continuously, per Apple |
| Pixel displacement | None | Yes (refraction) |
| Web equivalent | backdrop-filter plus border |
SVG displacement, Chromium only |
If you want tokens, dark mode and component patterns for the blur-based approach, start with the Glassmorphism 2.0 implementation guide. This article builds on it and adds what that guide does not cover: refraction, edge lighting, fallbacks and the full accessibility ladder.
Section 2: Layer 1, The Frosted Base
Every other layer sits on this one.
.glass {
background: rgb(255 255 255 / 0.14);
-webkit-backdrop-filter: blur(14px) saturate(180%);
backdrop-filter: blur(14px) saturate(180%);
border: 1px solid rgb(255 255 255 / 0.35);
border-radius: 24px;
box-shadow:
0 8px 32px rgb(0 0 0 / 0.18),
inset 0 1.5px 0 rgb(255 255 255 / 0.85),
inset 0 -1px 0 rgb(255 255 255 / 0.15);
}
What each line does:
backdrop-filter: blur() saturate(): blur softens what sits behind the element. The saturate boost keeps colors from going muddy once blurred. The values are starting points to tune by eye, not Apple's numbers.background: rgb(255 255 255 / 0.14): a thin tint that separates the surface from its backdrop.- The two inset shadows: a bright top edge and a faint bottom rim. They suggest a lit edge of glass and cost almost nothing.
- The outer shadow: lift. Larger glass should get a deeper shadow, which mirrors Apple's guidance that bigger glass reads as thicker material.
MDN labels backdrop-filter as Baseline 2024, newly available since September 2024. Keep the -webkit- prefixed line for older Safari versions.
The backdrop-root gotcha
If your blur does nothing, check the ancestors. Per MDN, a parent with opacity below 1, a filter, a mask, a clip-path, a mix-blend-mode, or a will-change value for any of those becomes a backdrop root, and the child can only blur what is inside that parent.
Josh Comeau also notes that the overflow: hidden workaround behaves differently in Chrome than in Firefox and Safari, so test it in all three. The reliable fix is structural: keep the glass element as a direct child of the layer that contains the colorful content, and put any fades or masks on siblings.
Section 3: Layer 2, Specular Highlights and Glass Edges
A flat blur reads as frosted plastic. Light on the edges is what makes it read as glass.
.glass {
position: relative;
isolation: isolate;
}
/* diagonal sheen across the surface */
.glass::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(
135deg,
rgb(255 255 255 / 0.45) 0%,
rgb(255 255 255 / 0) 40%,
rgb(255 255 255 / 0) 60%,
rgb(255 255 255 / 0.25) 100%
);
pointer-events: none;
z-index: -1;
}
/* gradient rim drawn as a masked ring */
.glass::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(
135deg,
rgb(255 255 255 / 0.9),
rgb(255 255 255 / 0.1) 40%,
rgb(255 255 255 / 0.1) 60%,
rgb(255 255 255 / 0.6)
);
-webkit-mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
mask-composite: exclude;
pointer-events: none;
}
Two details matter here.
Keep masks on pseudo-elements. A mask on the glass element itself would make it a backdrop root and break the blur it is supposed to produce. Putting the mask on ::after avoids that.
The rim is a ring, not a border. The padding plus the mask-composite exclusion leaves only a 1px gradient stroke, brighter at the corners facing the light and dim along the sides. That asymmetry is what a flat border cannot give you.
Section 4: Layer 3, Real Refraction With SVG (Chromium Only)
This is the layer that separates a Liquid Glass imitation from a frosted card. CSS filter functions never move pixels, so there is no native way to bend the backdrop. SVG can: an feDisplacementMap shifts pixels according to a map image, and Chromium accepts an SVG filter reference inside backdrop-filter.
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
<filter id="liquid" x="0" y="0" width="100%" height="100%"
color-interpolation-filters="sRGB">
<feTurbulence type="fractalNoise" baseFrequency="0.008 0.008"
numOctaves="2" seed="3" result="noise"/>
<feGaussianBlur in="noise" stdDeviation="2" result="map"/>
<feDisplacementMap in="SourceGraphic" in2="map" scale="42"
xChannelSelector="R" yChannelSelector="G"/>
</filter>
</svg>
.glass-refract {
background: rgb(255 255 255 / 0.08);
-webkit-backdrop-filter: blur(6px) saturate(160%);
backdrop-filter: blur(6px) saturate(160%);
}
/* only applied when script has confirmed a Chromium engine */
.is-chromium .glass-refract {
backdrop-filter: url(#liquid) blur(6px) saturate(160%);
}
Be honest about what this is. A turbulence map produces a gentle wobble, not a lens. True edge refraction uses a displacement map generated from the shape of the element, typically supplied through feImage, as the kube.io physics walkthrough and the LogRocket tutorial demonstrate. Treat the snippet above as the simplest working pattern, not a faithful lens.
The fallback ladder
Firefox parses url() inside backdrop-filter as valid and then renders nothing, so @supports is not a reliable gate for this feature. A practical approach is to detect Chromium in script and toggle a class. Treat this as a heuristic.
const isChromium = navigator.userAgentData?.brands?.some(
(b) => /Chromium/.test(b.brand)
);
document.documentElement.classList.toggle('is-chromium', Boolean(isChromium));
| Tier | Where it runs | What the user sees |
|---|---|---|
| 1. SVG refraction | Chromium-based browsers | Displaced backdrop plus blur and saturate |
| 2. Blur and saturate | Browsers with backdrop-filter support |
Frosted glass with specular edges |
| 3. Opaque surface | No support, or a reduced-transparency preference | Solid color, same layout |
WebKit has an open bug tracking SVG filters in backdrop-filter, and MDN's compatibility data repository has an issue on it too, so do not assume this limitation is permanent. Re-check before each major release.
One more constraint: backdrop-filter only affects content within the element's own box. Apple's glass can bend light from beyond its edges. Yours cannot.
Section 5: Mapping Apple Concepts to CSS
Here is the whole translation in one place, with an honest fidelity rating.
| Apple concept | CSS technique | Fidelity |
|---|---|---|
| Frosted material | backdrop-filter: blur() saturate() |
High |
| Lensing and refraction | SVG feDisplacementMap in backdrop-filter |
Partial, Chromium only |
| Specular highlight | Inset shadows, gradient sheen | Medium (static) |
| Glass rim | Masked gradient ring on ::after |
Medium |
| Depth and thickness | Outer box-shadow scaled by element size |
Medium |
| Adaptive tint | Tokens switched by theme or class | Low (not per pixel) |
| Regular vs Clear | Two token sets, Clear opt-in | Medium |
| Reduce Transparency | prefers-reduced-transparency |
Good where supported |
Batched rendering (GlassEffectContainer) |
Fewer, larger glass layers | Conceptual only |
Notice what lands at "High": only the blur. Everything that makes Liquid Glass feel alive scores lower on the web, which is why the next two sections matter more than any gradient value.
Section 6: Accessibility Is Not Optional
Apple's guidance for adopting Liquid Glass says to test with reduced transparency and reduced motion, and to limit these effects to the most important functional elements. The same discipline applies to CSS. For a broader checklist beyond glass, see the web accessibility guide.
Design the default to be legible
prefers-reduced-transparency is marked experimental with limited availability on MDN, so the default state must already work for users whose browsers ignore it. Check 14px body text over the busiest part of your background, not the average. WCAG 1.4.3 requires 4.5:1 for normal text and 3:1 for large text, and 1.4.11 requires 3:1 for non-text UI components such as input borders and focus rings.
The three-query ladder
Put these after your base rules so they win the cascade.
@media (prefers-reduced-transparency: reduce) {
.glass,
.glass-refract {
background: #1a1f38;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
}
@media (prefers-contrast: more) {
.glass {
background: rgb(20 24 40 / 0.92);
border-color: currentColor;
}
}
@media (forced-colors: active) {
.glass {
background: Canvas;
color: CanvasText;
border: 1px solid CanvasText;
-webkit-backdrop-filter: none;
backdrop-filter: none;
box-shadow: none;
}
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.glass {
background: rgb(30 34 52 / 0.92);
}
}
Why four blocks, not one:
prefers-reduced-transparencymirrors the OS-level setting (Reduce Transparency on macOS and iOS, Transparency effects on Windows). The fallback must be genuinely opaque. Nudging 15 percent opacity to 25 percent is not a fallback.prefers-contrast: moreis Baseline widely available since May 2022, so it reaches users the reduced-transparency query cannot. It acceptsno-preference,more,lessandcustom.forced-colors: activereplaces your palette with system colors. Shadows and translucent fills disappear, so the rule restores a visible border using system keywords.- The
@supports notblock covers engines with no backdrop filtering at all.
If your product has a dark theme, wire these into the same token layer so one switch changes everything. The dark mode accessibility guide covers that pattern, and design tokens with Figma variables and Style Dictionary shows how to keep the values in sync with design.
Section 7: Performance Budget
Blur is the most expensive filter function, and its cost grows with the radius and with the filtered area. A few rules of thumb, none of them from Apple:
- Keep the blur radius modest and the glass area small. Large full-screen blurs are where mid-range phones struggle.
- Use fewer, larger glass surfaces rather than many small ones. This echoes Apple's own advice to combine custom effects in a
GlassEffectContainerfor performance. - Avoid animating the size or shape of an element with an SVG displacement filter. Dynamic changes force the displacement map to be rebuilt, which kube.io flags as costly.
- Trim values on touch devices:
@media (max-width: 768px) and (hover: none) {
.glass {
-webkit-backdrop-filter: blur(8px) saturate(150%);
backdrop-filter: blur(8px) saturate(150%);
}
}
Be careful with will-change: backdrop-filter and translateZ(0) hacks. Per MDN, will-change for a backdrop-filter makes the element a backdrop root and can add compositor layers, so profile before adding it. For measuring real impact on your pages, a performance budget is a better tool than guessing layer counts.
Section 8: What You Cannot Replicate on the Web
Honest scoping saves you from promising a client something CSS cannot deliver.
- Per-pixel adaptive tint. Apple's material shifts its tint and shadow in response to the content behind it, continuously. CSS tokens switch between a few states. You can approximate with a theme class, not with real sampling.
- Refraction beyond the element's box.
backdrop-filteronly reads pixels inside the element. Real lensing at the edge of a floating control pulls in light from outside it. - Cross-browser refraction. The SVG route works in Chromium only, as covered above.
- System-wide consistency. On Apple platforms, system components adopt the material automatically. Your CSS version is a visual homage inside a page, not an OS feature.
- Motion-reactive light. Native glass responds to interaction and movement in ways a static gradient will not.
When to choose native
If you are shipping an app with SwiftUI, UIKit or AppKit, use the real thing: glassEffect(_:in:), UIGlassEffect or NSGlassEffectView. Apple documents all three in its Adopting Liquid Glass overview. Reserve the CSS version for websites, web apps and PWAs, where it is a styling choice rather than a platform material.
Conclusion: Build the Stack, Ship the Fallback
The honest recipe for Apple glassmorphism CSS has four parts. A frosted base works everywhere. Specular edges add the physical cue that flat blur lacks. SVG refraction adds real distortion for Chromium users who can render it. A tested fallback ladder protects everyone else, including people who turned transparency off for good reasons.
Resist the urge to apply it everywhere. Apple's own guidance is to limit these effects to the most important functional elements, and the iOS 26.1 Tinted option shows what happens when legibility loses to style.
Treat the glass as an enhancement on top of a surface that already works, and the fallback will be the version most of your users never notice.