Type something to search...
How to Create Glassmorphism Effects with backdrop-filter

How to Create Glassmorphism Effects with backdrop-filter

Glassmorphism is the design style behind the frosted panels you see in operating system menus, music players, and countless dashboard mockups. A translucent surface blurs whatever sits behind it, gets a faint highlight at the edges, and floats above a colorful background. Done well, it adds depth and a sense of place. Done badly, it turns text into mush.

The CSS feature that makes it possible is backdrop-filter. In this guide, I'll explain how it works, build a glass card step by step, cover the details that separate polished glass from a blurry rectangle, and walk through performance, accessibility, and fallbacks.

What backdrop-filter Actually Does

The regular filter property applies effects to an element and its content. backdrop-filter does something different: it applies effects to the area behind the element. The browser takes everything painted beneath the element's box, runs it through the filter functions, and uses the result as the element's backdrop.

.panel {
  backdrop-filter: blur(16px);
}

For the effect to be visible, two things must be true:

  1. The element's own background must be at least partly transparent. If the background is solid, it covers the filtered backdrop completely.
  2. There must be something interesting behind it. Blurring a flat white page just gives you a flat white page.

backdrop-filter accepts the same functions as filter: blur(), brightness(), contrast(), saturate(), grayscale(), hue-rotate(), invert(), opacity(), and sepia(). You can chain several, and they're applied in order.

.panel {
  backdrop-filter: blur(20px) saturate(160%) brightness(1.05);
}

Building a Glass Card Step by Step

Let's build a profile card that sits on top of a vivid background.

Step 1: The Markup

<main class="scene">
  <article class="glass-card">
    <img
      class="glass-card__avatar"
      src="/images/avatar.jpg"
      alt="Portrait of Lena Park"
      width="72"
      height="72"
    />
    <h2 class="glass-card__name">Lena Park</h2>
    <p class="glass-card__role">Product Designer, Northwind</p>
    <a class="glass-card__button" href="/contact">Get in touch</a>
  </article>
</main>

Step 2: A Background Worth Blurring

Glass needs color and shapes behind it. Layered radial gradients work perfectly and don't require any image files:

.scene {
  display: grid;
  place-items: center;
  min-height: 100vh;
  padding: 2rem;
  background-color: #0f172a;
  background-image:
    radial-gradient(circle at 20% 25%, #38bdf8 0, transparent 30%),
    radial-gradient(circle at 80% 30%, #f472b6 0, transparent 28%),
    radial-gradient(circle at 50% 85%, #818cf8 0, transparent 35%);
}

A photo works just as well. The busier the backdrop, the more obvious the frosted effect.

Step 3: The Translucent Surface

.glass-card {
  width: min(100%, 22rem);
  padding: 2rem;
  border-radius: 20px;
  text-align: center;
  color: #f8fafc;
  background-color: rgb(255 255 255 / 0.12);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  backdrop-filter: blur(18px) saturate(160%);
}

The semi-transparent white tints the glass slightly, and the blur softens everything behind it. The saturate() boost is a subtle touch that stops the blurred colors from looking washed out, similar to how real frosted interfaces keep colors lively.

The -webkit- prefixed version is there for older Safari releases. Current Safari supports the unprefixed property, but keeping both costs nothing.

Step 4: Edges and Highlights

Real glass catches light at its edges. A thin, semi-transparent border sells the illusion:

.glass-card {
  /* ...previous styles... */
  border: 1px solid rgb(255 255 255 / 0.25);
  box-shadow:
    0 10px 30px rgb(0 0 0 / 0.25),
    inset 0 1px 0 rgb(255 255 255 / 0.3);
}

The outer shadow lifts the card off the background. The inset shadow draws a one-pixel highlight along the top edge, as if light is hitting the upper rim.

For a more premium look, use a gradient border that's brighter at the top-left and fades toward the bottom-right. One reliable way is a pseudo-element with a mask:

.glass-card {
  position: relative;
  isolation: isolate;
}

.glass-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(
    135deg,
    rgb(255 255 255 / 0.6),
    rgb(255 255 255 / 0.05) 50%,
    rgb(255 255 255 / 0.25)
  );
  -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 exclude,
    linear-gradient(#000 0 0);
}

The two mask layers cut out the content area, leaving only a 1px ring of gradient. If you use this, remove the solid border from step 4.

Step 5: Content Styles

.glass-card__avatar {
  border-radius: 50%;
  border: 2px solid rgb(255 255 255 / 0.5);
}

.glass-card__name {
  margin: 1rem 0 0.25rem;
  font-size: 1.5rem;
}

.glass-card__role {
  margin: 0 0 1.5rem;
  color: rgb(248 250 252 / 0.8);
}

.glass-card__button {
  display: inline-block;
  padding: 0.65rem 1.25rem;
  border-radius: 999px;
  color: #0f172a;
  font-weight: 600;
  text-decoration: none;
  background-color: rgb(255 255 255 / 0.85);
}

.glass-card__button:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

That's a complete glass card. Everything behind it is blurred and tinted, the edges catch light, and the content remains crisp because backdrop-filter never touches the element's own children.


Tuning the Effect

Glassmorphism lives or dies on a few values. Here's how each one changes the feel:

PropertyLow valueHigh value
Blur radiusBackground shapes still readableSoft, dreamy, almost solid color
Background alphaClear glass, low contrast for textMilky glass, better text contrast
SaturationMuted, gray-ish blurVivid, glowing colors
Border alphaEdges disappearHard, outlined look

A good starting point is a blur between 12px and 24px, a background alpha between 0.1 and 0.25, and a border alpha around 0.2. Adjust from there.

Dark Glass

For dark themes, tint with black instead of white:

.glass-dark {
  color: #e2e8f0;
  background-color: rgb(15 23 42 / 0.55);
  border: 1px solid rgb(148 163 184 / 0.2);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
}

Dark glass is more forgiving for text contrast, which makes it a great fit for navigation bars and overlays.

A Sticky Glass Header

One of the most practical uses of backdrop-filter is a header that blurs page content as it scrolls underneath:

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.5rem;
  background-color: rgb(255 255 255 / 0.7);
  border-bottom: 1px solid rgb(15 23 42 / 0.08);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

Because the background alpha is fairly high (0.7), text in the header stays readable even when a bright image scrolls behind it.


Gotchas You'll Run Into

Nothing Happens

If the blur doesn't appear, check these in order:

  • Is the element's background transparent enough? A solid background hides the effect entirely.
  • Is there anything behind the element? The effect only blurs content painted beneath it.
  • Is a parent clipping or isolating the backdrop? The backdrop root matters: an ancestor with filter, opacity less than 1, mask, clip-path, mix-blend-mode, or another backdrop-filter forms a backdrop root, and the blur can only see content inside that ancestor, not the page behind it.

That last one causes most "it works in one place but not another" bugs. For example, if you fade a modal in by animating opacity on its wrapper, the glass panel inside may briefly blur nothing at all.

Blurry Edges Bleed or Look Dark

The blur samples pixels around the edges of the element's box. Near the viewport edge, there's nothing to sample, which can produce a slightly dark or transparent rim. Giving the glass element some breathing room from the viewport edge, or slightly enlarging the background layer, avoids it.

Nested Glass Doesn't Blur Its Parent Glass

If you put a glass element inside another glass element, the inner one blurs only what's inside the outer element, because the outer one forms a backdrop root. Design for one layer of glass at a time rather than stacks of nested panels.

Text Contrast

This is the big one. Translucent surfaces over unpredictable backgrounds are an accessibility risk. The text contrast changes as the content behind it changes, and a bright spot behind white text can drop contrast far below acceptable levels.

Some ways to keep things readable:

  • Raise the background alpha so the glass is more opaque.
  • Use a heavier blur so background details can't compete with text.
  • Add a subtle dark or light tint that matches your text color's opposite.
  • Keep text on glass short: headings, labels, and buttons rather than long paragraphs.
  • Test against the brightest and darkest parts of the backdrop.

Respecting User Preferences

Some users enable reduced transparency at the operating system level because translucent interfaces are harder for them to read. CSS exposes this through a media query:

@media (prefers-reduced-transparency: reduce) {
  .glass-card,
  .site-header {
    background-color: rgb(30 41 59 / 0.95);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

Support for prefers-reduced-transparency is still limited and uneven across browsers, so check caniuse and treat it as an enhancement. Browsers that don't recognize it simply skip the block.

You should also honor high contrast settings. In Windows forced colors mode, backgrounds are replaced anyway, but a visible border helps define the panel:

@media (forced-colors: active) {
  .glass-card {
    border: 1px solid CanvasText;
  }
}

Performance

backdrop-filter is GPU-accelerated in modern browsers, but it isn't free. Every frame, the browser must read the pixels behind the element and blur them. A few guidelines keep things smooth:

  • Limit the area. A glass header or a few cards is fine. A full-screen glass overlay on top of a scrolling video is expensive.
  • Keep blur radii reasonable. Larger radii require more samples. The difference between 16px and 40px may be barely visible but measurably slower on low-end devices.
  • Avoid animating the blur radius. Transitioning backdrop-filter: blur(0) to blur(20px) works, but it's costly. Fading in the element's opacity looks similar, though remember the backdrop root caveat above.
  • Test on real phones. Mid-range Android devices are where heavy glass effects start to stutter while scrolling.

Browser Support and Fallbacks

backdrop-filter is supported in all current major browsers, including Chrome, Edge, Firefox, and Safari. Safari needed the -webkit- prefix for a long time, which is why you'll still see both lines in production code.

For older browsers, or environments where the effect is disabled, use @supports to provide a solid fallback. Start with the fallback, then upgrade:

.glass-card {
  /* Fallback: fairly opaque, always readable */
  background-color: rgb(30 41 59 / 0.9);
}

@supports (
  (-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))
) {
  .glass-card {
    background-color: rgb(255 255 255 / 0.12);
    -webkit-backdrop-filter: blur(18px) saturate(160%);
    backdrop-filter: blur(18px) saturate(160%);
  }
}

This way, nobody gets transparent text over a busy, unblurred background, which is the worst possible outcome.

Conclusion

Glassmorphism comes down to a short recipe: a colorful backdrop, a translucent background, a backdrop-filter blur, and a light edge highlight. The craft is in the details, like adding a saturation boost, choosing the right tint for light or dark themes, and understanding backdrop roots when an effect mysteriously disappears.

Most importantly, keep the glass readable. Raise the opacity when text sits on top, offer a solid fallback with @supports, and respect reduced-transparency preferences. Use glass for surfaces that benefit from depth, like headers, modals, and highlight cards, and your interface will feel layered and modern without sacrificing usability.

Tags :
Share :

Related Posts

A Complete Guide to CSS Container Queries

A Complete Guide to CSS Container Queries

For more than a decade, responsive design meant one thing: media queries. You asked the browser how wide the viewport was and adjusted your layout ac

Continue Reading
A Comprehensive Guide to Installing Next.js

A Comprehensive Guide to Installing Next.js

Next.js has emerged as a powerful framework for building React applications, offering features like server-side rendering, static site generation, an

Continue Reading
Advanced CSS with clamp(), min(), and max(): Simplifying Dynamic Styling

Advanced CSS with clamp(), min(), and max(): Simplifying Dynamic Styling

CSS has evolved significantly, and modern tools like clamp(), min(), and max() are powerful game-changers in dynamic styling. If you’ve struggl

Continue Reading