Glassmorphism and neumorphism that stay readable

How glass and soft-UI effects are built in CSS, why they often fail WCAG contrast, measured examples, and fixes that keep the look.

On this page

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 textEffective backgroundWhite text contrast
Deep blue #1e3a8amixed with 20% white5.96:1
Violet #7c3aedmixed with 20% white3.98:1
Red #f43f5emixed with 20% white2.97:1
Green #22c55emixed with 20% white1.95:1
Yellow #facc15mixed with 20% white1.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 opacityWorst-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 intensityDark 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 #737d8c on #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-filter is 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.

Tools mentioned in this article

Back to the blog