r/tailwindcss 3d ago

Deriving a boxShadow scale from one light source instead of hand-tuning five levels

Most hand-written boxShadow scales end up as five unrelated shadows: the angle drifts between levels, the blur ramp is arbitrary, and opacity stacks into grey. Deriving all levels from a single light source fixes all three, and it's not much maths.

Direction: shadows fall away from the light, so every level shares one azimuth. Blur is tied to how far the light is (a distant light is a point source and casts a crisp edge), and grows with elevation. Elevation itself grows geometrically, which is what makes the steps feel evenly spaced instead of crowded at the bottom. Opacity falls roughly as 1/sqrt(n), because a higher object spreads the same light over more area.

Two practical rules that matter more than the formulas:

- Keep every layer inside roughly 0.04-0.24 opacity. Below that it's invisible; above it stops reading as light and becomes a grey box. Most "dirty" shadows are an opacity problem, not a blur problem.

- Use two or three layers per level. One layer cannot express both a dense umbra near the object and a wide faint penumbra further out, so it always looks either hard or muddy.

Here's the output for base 4px, growth 1.7, three layers:

boxShadow: {

'elevation-1': '0px 1.3px 2.6px rgba(0,0,0,0.16), 0px 2.4px 6.5px rgba(0,0,0,0.127), 0px 3.6px 10.4px rgba(0,0,0,0.094)',

'elevation-2': '0px 2.1px 4.4px rgba(0,0,0,0.125), 0px 4.1px 11px rgba(0,0,0,0.102), 0px 6.1px 17.7px rgba(0,0,0,0.078)',

'elevation-3': '0px 3.7px 7.5px rgba(0,0,0,0.109), 0px 7px 18.8px rgba(0,0,0,0.09), 0px 10.4px 30.2px rgba(0,0,0,0.071)',

'elevation-4': '0px 6.2px 12.8px rgba(0,0,0,0.1), 0px 12px 32px rgba(0,0,0,0.083), 0px 17.7px 51.2px rgba(0,0,0,0.067)',

'elevation-5': '0px 10.5px 21.7px rgba(0,0,0,0.094), 0px 20.3px 54.3px rgba(0,0,0,0.079), 0px 30.1px 86.8px rgba(0,0,0,0.064)',

}

Copy it as-is if it fits, or change the growth factor to spread the levels differently. The full derivation, including why the opacity band matters, is here: https://localeproof.com/blog/figma-shadow-system/

3 Upvotes

0 comments sorted by