Using glass with restraint: a hierarchy rule
Glassmorphism works as an elevation language: glass says “this floats above the content”. The designs that age well use it for exactly one or two layers — a navigation bar, a modal, a hero card — over a rich background. The designs that look like 2021 demos apply glass to everything, stacking translucent panels on translucent panels until nothing reads as elevated because everything is. A practical rule: one glass level per screen, opaque surfaces for everything else, and never glass-on-glass — a second translucent layer over the first multiplies blur cost and visually muddies both.
The complete production snippet, explained
A robust glass panel needs four ingredients beyond what any generator outputs blindly:
.glass {
background: rgba(255, 255, 255, 0.12); /* tint — tune per theme */
backdrop-filter: blur(14px) saturate(160%);
-webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari */
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
}
@supports not (backdrop-filter: blur(1px)) {
.glass { background: rgba(30, 30, 36, 0.85); } /* solid fallback */
}
The saturate() half of the filter is the underrated part — pure blur grays out the background; boosting saturation keeps the colors behind the glass alive, which is most of what makes the effect feel “Apple-like”. The @supports fallback matters because without it, unsupported browsers render text floating on a nearly-invisible tint.
Dark mode changes the recipe
Glass parameters don’t transfer between themes — they invert. Light-mode glass uses a white tint (8–15% opacity) with a light border; dark-mode glass needs a much subtler white tint (4–8%) or a dark tint, a fainter border (8–12% white), and stronger reliance on the shadow for definition. Saturation boosts that look lush in light mode can look radioactive against dark backgrounds — drop saturate() to 120–130%. The practical workflow: design the light variant here, then create the dark variant by halving tint opacity and border alpha rather than reusing values — and store both as CSS custom properties switched by your theme class.