Skip to content
HexSlate

Glassmorphism Generator

Glass panelText sits on top of the blur, sharp.
CSS
.glass {
  background-color: rgb(255 255 255 / 0.12);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  backdrop-filter: blur(12px) saturate(180%);
  border: 1px solid rgb(255 255 255 / 0.25);
  border-radius: 16px;
  box-shadow: 0 8px 32px rgb(11 28 30 / 0.24);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass {
    background-color: rgb(255 255 255 / 0.85);
  }
}
Tailwind v4
bg-[rgb(255_255_255_/_0.12)] backdrop-blur-[12px] backdrop-saturate-[180%] border border-[rgb(255_255_255_/_0.25)] rounded-[16px] shadow-[0_8px_32px_rgb(11_28_30_/_0.24)]
blur 12pxtint 0.12fallback included

Five declarations, and they only work together

Glass is a translucent fill, a backdrop-filter blur, a saturation boost, a light border, and a shadow. Drop the saturation and it looks like frosted plastic, because blurring alone averages colour towards grey and real glass concentrates it. Drop the border and the panel loses its edge entirely, since there is nothing else separating it from what it floats over. The border is doing the work a shadow does on an opaque card.

Keep the tint somewhere between 12 and 25%. Past a third it stops blurring anything you can see and becomes flat paint over a photo, which is the single most common way this effect goes wrong. If the text on the panel is not readable, raise the blur or move the tint towards the text's opposite, rather than raising the opacity.

The fallback is not optional

backdrop-filter is what makes a 12% fill readable. Where the property is not supported, that same fill is text on unblurred noise, which fails contrast at any font size and cannot be fixed by the reader. So the output always carries @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) with a solid 85% surface behind it. Both conditions are tested, because a browser that only ever shipped the prefixed property would otherwise take the fallback it does not need.

Safari needed -webkit-backdrop-filter until version 18 in 2024, and enough installed devices are older that the prefixed line is still worth its 40 bytes. It is written first so the standard property wins wherever both are understood.

Common problems

  • Nothing is blurred. The element's own background is fully opaque, so there is nothing to see through. backdrop-filter filters what is behind, and an opaque fill hides exactly that.
  • It works alone but not inside a parent. An ancestor with overflow: hidden, a filter, or an opacity below 1 creates a new backdrop root, and the blur then samples that group instead of the page. Moving the panel out of the clipping ancestor is usually the fix.
  • Scrolling stutters on a phone. A large blurred backdrop repaints every frame it is composited. Reduce the radius, shrink the panel, or drop the effect below a width breakpoint. A 28px blur across a full-width header is the expensive case.
  • The edges of the panel look washed out. The blur samples outside the panel too. A slightly stronger border, or a second inset highlight along the top edge, restores the boundary.

Frequently asked questions

Should the tint be white or dark?

It should match the scene. A white film over a near-black background reads as fog rather than as glass, which is why the On dark preset tints with the site's darkest ink and keeps the border white at a low opacity. The border is the highlight; the fill is the glass.

Is glassmorphism accessible?

Only if you check it. Text on a translucent panel has a contrast ratio that changes with whatever moves behind it, so the worst case is what matters, not the average. Test against the lightest and darkest regions of your background, and remember WCAG AA wants 4.5:1 for normal text. A busy photograph behind a 12% panel usually cannot pass, and the honest answer there is a more opaque surface for the text block specifically.

Why does the Tailwind output use real utilities here?

Because every part of this effect has one: backdrop-blur-[…], backdrop-saturate-[…], bg-[…], border-[…], rounded-[…] and shadow-[…]. Unlike the filter pipeline, nothing here depends on ordering, so the utility form loses nothing. The @supports fallback still has to go in a stylesheet.

Can I animate the blur?

You can, and you will feel it. Every frame re-samples and re-blurs the backdrop. Animate the panel's opacity or transform instead and leave the blur at a fixed radius, which gets you the same "it slid in" impression for a fraction of the cost.