Neumorphism CSS Generator
Build a soft UI surface from one colour and two derived shadows, with the contrast ratio that decides whether the result is usable printed next to it.
Enable JavaScript to change the surface; the CSS below is for the defaults.
The element and its background are the same colour, which is the premise of the effect and the reason it struggles with contrast.
How far the two shadow colours move from the surface. Both are derived from it, because a soft UI only reads as one material if they are.
.soft {
background: #e0e5ec;
border-radius: 18px;
box-shadow: 9px 9px 18px #999DA2, -9px -9px 18px #EDF0F4;
}
/* The shadow is 2.15:1 against the surface. WCAG asks for 3:1
between a control and what is around it, and does not count a shadow
as a boundary at all, so a soft UI needs a real border, a label or a
background difference somewhere to be usable. */
Neumorphism is one colour and two shadows: a lighter one where the light comes from, a darker one opposite. The element and its background are the same colour, and the shadows do all the work of making it look raised or pressed.
That premise is also the problem, and it is worth stating before the sliders. WCAG asks for 3:1 contrast between a control and what surrounds it, and it does not count a shadow as a boundary. An element that is exactly the colour of its background has a contrast ratio of 1:1 against it. On the defaults here, the darker shadow manages 2.15:1, and the tool prints that figure next to the preview rather than leaving it to be discovered in an audit.
None of that makes the effect useless. It makes it a decoration that needs something else doing the work of telling people where the controls are: a label, a real border, or a background that actually differs.
How to use
- Pick the surface colour. The two shadow colours are derived from it, because a soft UI only reads as one material if they are.
- Choose raised, pressed, flat, concave or convex, then set distance, blur and intensity.
- Read the contrast line under the preview before deciding the effect is finished.
Example
.soft {
background: #e0e5ec;
border-radius: 18px;
box-shadow: 9px 9px 18px #999DA2, -9px -9px 18px #EDF0F4;
}
/* The shadow is 2.15:1 against the surface. WCAG asks for 3:1
between a control and what is around it, and does not count a shadow
as a boundary at all, so a soft UI needs a real border, a label or a
background difference somewhere to be usable. */
A pressed state is the same two shadows with inset on both, which is why the effect is so satisfying to
build and so hard to use: raised and pressed differ by a keyword, and to a person glancing at the screen
they differ by almost nothing.
Pitfalls
Contrast is the whole objection. Not a detail to fix later. A control nobody can find is not a control, and shadows do not count towards the ratio.
Raised and pressed look nearly the same. The difference is subtle by design, which makes state hard to read. Pair it with something unambiguous: a colour change, a label change, a checkmark.
It needs a mid-tone surface. On white or near-black there is nowhere for the light shadow or the dark shadow to go, and the effect collapses.
Both shadow colours must come from the surface. Hand-picked greys read as two materials rather than one lit surface, which is why they are derived here rather than entered.
Dark mode is not a colour swap. The light shadow has to stay lighter than the surface and the dark one darker, so the pair has to be recomputed from the dark surface rather than inverted.
It costs paint. Two large blurred shadows on many elements is real work for the compositor, and a list of neumorphic cards on a phone is where it shows.
Focus states need separate attention. If the visible boundary of a control is a shadow, the focus ring has even less to sit against. Give it a solid outline with an offset.
Compatibility
box-shadow, border-radius and linear-gradient work everywhere, so the effect itself has no support
question. The accessibility question is the one that matters and it is independent of browser.
The two shadow colours are derived by mixing the surface towards white and towards black by a share of the intensity, which keeps them on the same hue. The test suite asserts the light one is measurably lighter than the surface, the dark one measurably darker, and that at zero intensity they collapse to the same colour.
The contrast ratio is computed with the same WCAG relative-luminance formula the contrast checker uses, between the darker shadow and the surface, which is the most generous reading of “is this element distinguishable”. It is still usually below 3:1.
The whole calculation is mirrored in PHP for the first paint, with a case file covering a dark surface, a convex gradient, a negative distance and full intensity.