← All posts
CSSTutorial

Glassmorphism in CSS: a practical guide

July 29, 2026 · 8 min read

Frosted glass is one of those effects that looks like magic and turns out to be four CSS properties in a trench coat. This is the complete recipe — the properties that matter, why each one is there, the fallback you must ship, and the mistakes that make glass look cheap. Everything here is plain CSS you can paste into any project.

The core recipe

A glass surface is a translucent fill, a backdrop blur, a light border, and a soft shadow. All four, or it doesn't read as glass:

.glass {
  background: rgba(255, 255, 255, 0.06);        /* 1 — translucent fill    */
  backdrop-filter: blur(16px) saturate(140%);   /* 2 — the frost           */
  -webkit-backdrop-filter: blur(16px) saturate(140%); /* Safari ≤ 17       */
  border: 1px solid rgba(255, 255, 255, 0.14);  /* 3 — the catch-light     */
  border-radius: 0.875rem;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);   /* 4 — lift off the page   */
}

What each part does:

This box is the recipe above, live — the page's gradient backdrop is blurring through it right now.

Glass needs something to blur

The #1 reason glass "doesn't work" in someone's project: the page behind it is a flat color. Blurring a solid gives you… the same solid. Glass only reads over a rich backdrop — a gradient, an image, or color "orbs" painted behind the page:

body {
  background-color: #060912;
  background-image:
    radial-gradient(48rem 48rem at 82% -12%, rgba(109, 74, 245, 0.28), transparent 60%),
    radial-gradient(36rem 36rem at -8% 18%, rgba(34, 211, 238, 0.20), transparent 58%);
  background-attachment: fixed;   /* orbs stay in the viewport on long pages */
}

background-attachment: fixed matters on long pages — without it the color lives only at the very top and your glass turns gray as the user scrolls.

The fallback you must ship

backdrop-filter is well-supported now, but "well-supported" is not "universal" — and when it's missing, a translucent panel silently becomes unreadable text floating on the raw background. Invert the logic: make the surface opaque by default and add the frost only where it works:

.glass {
  background: #121a2e;                     /* opaque — always readable */
}
@supports (backdrop-filter: blur(1px)) {
  .glass {
    background: rgba(255, 255, 255, 0.06); /* the real glass */
    backdrop-filter: blur(16px) saturate(140%);
  }
}

Text on glass

Because the surface is translucent, the effective background of your text shifts with whatever scrolls underneath. Two rules keep it readable: keep body text near-white (or near-black on light glass) rather than a brand color, and check contrast against the composited surface, not the fill's rgba value. Brand colors that pass as button fills usually fail as text — use a lightened variant for text and links. (The full accessibility treatment is its own article.)

The mistakes that make glass look cheap

Or take the shortcut

Everything above — plus the contrast math, the reduced-motion handling, dark/light themes and 42 ready components using the same glass system — is what Farvist packages into one ~21 KB stylesheet. The recipe is genuinely four properties; the polish is the other 95%. If you'd rather not maintain that yourself:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/farvist/dist/farvist.min.css">
<body class="bg-mesh-aurora">
  <div class="card glass">…</div>

Either way — hand-rolled or framework — the difference between cheap glass and good glass is the backdrop, the border, the fallback, and restraint with the blur radius. Get those four right and everything you build looks a little bit from the future.


← All posts Explore the framework →