Glassmorphism (frosted, translucent panels) and neumorphism (soft surfaces that seem pressed out of the background) look great in a design file and often fail the people who actually use the interface. The problem is not taste but arithmetic: both styles lower contrast by construction. This article shows how each is built in CSS, measures the contrast with real colours, and gives the smallest changes that make them pass. All numbers come from the CSS effects generator, which reports them as you adjust the sliders.
How glass is made
A glass panel is a semi-transparent background plus a blur of whatever is behind it:
.glass {
background: rgba(255, 255, 255, 0.2);
-webkit-backdrop-filter: blur(12px) saturate(180%);
backdrop-filter: blur(12px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 16px;
}backdrop-filter works in current Chrome, Edge, Firefox and Safari; Safari before version 18 needs the -webkit- line. Add a fallback for anything older, so text never sits on a fully transparent panel:
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.glass { background: rgba(255, 255, 255, 0.85); }
}Measuring text on glass
What the reader sees behind a letter is roughly the tint laid over the blurred backdrop. With 20% white glass that is 0.2 × white + 0.8 × backdrop. Blur averages nearby pixels, so for a photo, use its average colours; for the generator's colourful sample backdrop, these are the results for white text:
| Backdrop colour under the text | Effective background | White text contrast |
|---|---|---|
Deep blue #1e3a8a | mixed with 20% white | 5.96:1 |
Violet #7c3aed | mixed with 20% white | 3.98:1 |
Red #f43f5e | mixed with 20% white | 2.97:1 |
Green #22c55e | mixed with 20% white | 1.95:1 |
Yellow #facc15 | mixed with 20% white | 1.42:1 |
WCAG AA asks 4.5:1 for body text and 3:1 for large text. The same panel passes over the blue and fails badly over the yellow, and a user scrolling past a colourful hero sees both within a second. A white tint can never make white text more readable: it pulls every backdrop towards white.
Fixing glass
Switch the tint to a dark colour and raise its opacity. With #0f172a (slate 900) as the tint, over the same five backdrops, the worst-case contrast for white text is:
| Tint opacity | Worst-case contrast |
|---|---|
| 20% | 2.29:1 |
| 40% | 3.66:1 |
| 60% | 6.34:1 |
At 60% it passes AA everywhere and still looks like glass, because the blur keeps the shapes of the backdrop visible. Other options that help:
- Blur more. A stronger blur averages the backdrop, removing sharp light spots behind single letters.
- Calm the backdrop. Glass over a busy photo is harder than glass over a soft gradient.
- Use larger, bolder text on glass, which only needs 3:1.
- Avoid glass for long text. Use it for a headline or a navigation bar, not a paragraph.
How neumorphism is made
Soft UI uses two shadows derived from one base colour, on a background of the same colour:
.soft {
border-radius: 20px;
background: #e0e5ec;
box-shadow: 8px 8px 16px #bec3c9,
-8px -8px 16px #e5e9ef;
}The dark shadow is the base colour mixed with 15% black, the light one with 15% white. Swap them inside inset for a pressed state.
Why neumorphic controls are hard to see
WCAG 1.4.11 (Non-text Contrast) asks that the visual boundary of a control reach 3:1 against what is next to it. A neumorphic button's only boundary is its shadow:
| Shadow intensity | Dark edge vs background |
|---|---|
| 10% | 1.25:1 |
| 15% | 1.40:1 |
| 20% | 1.59:1 |
Even a heavy 20% shadow is about half of what is required, and the difference between a raised button and a pressed one is subtler still. People with low vision, a dim phone screen in sunlight or a cheap monitor see a flat grey page.
Fixing neumorphism
Keep the soft shadows as decoration, and give every interactive element something with real contrast:
- A border or outline of at least 3:1 against the background, for example
1px solid #737d8con#e0e5ec(3.29:1). - An icon and a text label in a dark colour, so the control is recognisable without its shape.
- A clear pressed or selected state that changes colour, not just shadow direction.
- A visible focus ring for keyboard users; the default outline often disappears on these backgrounds.
Check each pair in the colour tools contrast checker before you commit to a palette.
Common mistakes
- Testing on one backdrop. Glass contrast must be checked against the brightest and darkest parts of everything that can scroll behind it.
- White text on white glass. Use a dark tint for light text, or dark text on a light tint, never light on light.
- Forgetting the fallback. Without
@supports, older browsers show text on an almost transparent box. - Shadow-only states in soft UI. If "on" and "off" differ only by shadow direction, many users cannot tell which is which.
- Blurring huge areas.
backdrop-filteris recomputed when what is behind changes; a full-screen blurred layer over video drains battery and drops frames on low-end phones.
Try it
Open the CSS effects generator, choose the Glass tab with the colourful backdrop, and move the tint opacity while watching the contrast line. Then open the Neumorphism tab and see how far the intensity slider has to go before the edge reaches 3:1 (it never does at sensible values), which is the clearest argument for adding borders and labels.