Tutorial · Beginner · 6 min

Build a frosted-glass card with CSS

The frosted-glass look — a translucent panel that blurs whatever sits behind it — turns a flat card into something that feels layered and physical. It takes four CSS properties. Here's each one, and why it matters.

1. You need something behind the glass

Glass only reads as glass when there's color and detail behind it to blur. Start with a vivid backdrop, then place a card on top. Without this step the effect is invisible, which is the single most common reason glassmorphism "doesn't work."

.scene {
  min-height: 320px;
  display: grid;
  place-items: center;
  background: linear-gradient(120deg, #4F46E5, #6366F1 60%, #0EA5E9);
}

2. Make the panel translucent

The card's own background has to be semi-transparent so the blur shows through. Keep the alpha low — somewhere around 0.15 to 0.3. Too opaque and you've just made a solid card; too clear and the text loses contrast.

.glass {
  background: rgba(255, 255, 255, 0.18);
  padding: 28px 32px;
  border-radius: 20px;
  color: #fff;
}

3. Add the blur

This is the property doing the real work. backdrop-filter blurs the pixels behind the element, not the element itself. A touch of saturate() revives the colors the blur would otherwise mute. Always include the -webkit- prefix for Safari.

.glass {
  backdrop-filter: blur(12px) saturate(160%);
  -webkit-backdrop-filter: blur(12px) saturate(160%);
}

4. Catch the edge with a light border

Real glass has a bright rim where light hits its edge. A single hairline border in low-opacity white sells the illusion. Finish with a soft shadow so the card lifts off the backdrop.

.glass {
  border: 1px solid rgba(255, 255, 255, 0.35);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
}

Putting it together

That's the whole recipe: a colorful backdrop, a translucent fill, backdrop-filter, and a light border. Adjust the blur and alpha until the text stays readable over the busiest part of your background — that's the real test.

A note on performance and contrast

backdrop-filter is GPU-accelerated, but it still costs more than a flat fill, so reserve it for a few hero panels rather than every card in a list. And because the backdrop changes the contrast behind your text, check readability against your darkest and lightest background regions, not just the average — accessibility lives in the worst case.

Handling older browsers

Every current browser supports backdrop-filter, but you may still want a graceful fallback for the rare old one. The clean way is a feature query: set a more opaque background by default, then lighten it only where the blur is actually available.

.glass { background: rgba(255, 255, 255, 0.7); }   /* readable fallback */

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .glass {
    background: rgba(255, 255, 255, 0.18);
    backdrop-filter: blur(12px) saturate(160%);
    -webkit-backdrop-filter: blur(12px) saturate(160%);
  }
}

With this in place, a browser that can't blur shows a solid, legible card instead of unreadable text over a busy background. That's the right default: the content works everywhere, and the polish layers on top where it's supported.

Where to take it next

The same four ingredients scale to navbars, modals and toolbars — anywhere a floating surface sits over content. Try a darker tint (rgba(20, 20, 30, 0.3)) for a "smoked glass" version, or animate the blur on scroll so a header frosts as the page moves beneath it.

Want to dial in the exact values without writing them by hand? The glassmorphism generator gives you live sliders and copies the finished CSS. For the backdrop itself, build one in the gradient generator.