CSS Gradients, Shadows and Border Radius, Explained

After reading this you will know exactly what each number in a gradient, box-shadow or border-radius does, why layered shadows look real while single blurs look flat, and how to write these values by hand when you need to.

What these three properties actually control

Three CSS features cover most of the visual polish you add to a plain box: background gradients, box-shadow, and border-radius. All three take a small list of numbers with strict meanings. Once you know what each number does, the generator becomes a way to preview values you already understand, not a black box.

Here is one hook example. This single declaration paints a diagonal blend from teal to purple:

\text{background: linear-gradient(135deg, } \#2dd4bf \text{ 0\%, } \#7c3aed \text{ 100\%)}

The angle 135^\circ points the gradient down and to the right. The two color stops sit at 0% and 100% of that line. Every gradient, no matter how many colors, is just an angle (or a shape) plus a list of stops with positions.

When to reach for each, and when not to

Use a gradient when you want a smooth color transition inside one element: a button, a hero banner, a progress bar. Do not use a gradient to fake a photographic image; that is what real images are for, and a 12-stop gradient is both hard to maintain and easy to get wrong.

Use box-shadow to show depth or focus: a card lifted off the page, a dropdown floating above content, a ring around a focused input. Do not use a single huge blur to imply "elevated"; that reads as a gray smudge. The realistic look comes from stacking.

Use border-radius to round corners. One value rounds all four the same. Four values round each corner independently. Do not set a radius larger than half the shorter side unless you actually want a pill or a circle, because the browser clamps it there anyway.

All three properties animate cheaply on modern browsers except box-shadow, which repaints on every frame. If you animate elevation, animate transform and cross-fade a second shadow layer instead of tweening the blur.

The gradient line and how stops map onto it

A linear gradient draws along a line through the box. For an angle \theta, 0deg points up, 90deg points right, and the angle increases clockwise. The gradient line runs across the box so that its full length spans from one corner region to the opposite one, and each color stop names a position along that line as a percentage.

\text{color}(p) = \text{lerp}(c_i, c_{i+1}, \frac{p - s_i}{s_{i+1} - s_i}) \quad \text{for } s_i \le p \le s_{i+1}

Here p is a position from 0% to 100% along the line, c_i and s_i are the color and position of stop i, and lerp is linear interpolation in the chosen color space. Between two stops the color blends; before the first stop and after the last, the color holds flat. Radial gradients replace the line with a distance from a center point, and conic gradients replace it with an angle sweeping around a center.

A worked gradient from the demo defaults

Reproducing the two-stop diagonal

Load the tool and press the demo button. The default gradient is linear-gradient(135deg, #2dd4bf 0%, #7c3aed 100%). Work out the color at the exact middle of the line, p = 50\%.

  1. Convert the two hex colors to RGB. #2dd4bf is (45, 212, 191). #7c3aed is (124, 58, 237).
  2. The fraction between stops is \frac{50 - 0}{100 - 0} = 0.5.
  3. Interpolate each channel in sRGB: red is 45 + 0.5 \times (124 - 45) = 84.5, green is 212 + 0.5 \times (58 - 212) = 135, blue is 191 + 0.5 \times (237 - 191) = 214.
  4. Round to (85, 135, 214), which is #5587d6, a muted blue. That is the pixel you see at the center of the diagonal.

Browsers interpolate in sRGB by default, so this arithmetic matches what you see. If you switch to OKLCH interpolation with in oklch, the midpoint shifts because the blend happens in a perceptual space instead. To convert and check colors, use the Color Converter & Contrast Checker.

Why layered shadows look real

A box-shadow takes up to four lengths: horizontal offset, vertical offset, blur radius, and spread radius, followed by a color. A real object casts light that falls off gradually, so its shadow is dense and small near the object and faint and wide far away. A single shadow cannot show both at once.

\alpha_{\text{total}}(d) = 1 - \prod_{j=1}^{n} \left(1 - \alpha_j(d)\right)

This says the visible opacity at distance d from the box is what you get by stacking n semi-transparent shadow layers, each with its own falloff \alpha_j(d). Near the box, several tight layers overlap and add up. Far away, only the widest, faintest layer remains. The trick is to increase blur and decrease opacity together across layers.

A three-layer soft shadow

Compare one big shadow against three tuned layers. The single version is 0 10px 30px rgba(0,0,0,0.30). The layered version stacks these:

Blur and opacity across a three-layer shadow
LayerY offsetBlurOpacity
11px2px0.12
24px8px0.10
310px20px0.08

Written out: box-shadow: 0 1px 2px rgba(0,0,0,.12), 0 4px 8px rgba(0,0,0,.10), 0 10px 20px rgba(0,0,0,.08). The maximum single-layer opacity is only 0.12, yet the contact edge reads crisp because layer 1 is tight. Total opacity right at the box, using the formula, is 1 - (0.88)(0.90)(0.92) = 0.271, close to the single shadow's 0.30, but the falloff is smooth instead of a flat gray disc.

A single shadow with 30px blur at 30% opacity looks like a uniform gray blob. Splitting the same darkness across three layers (blurs 2px, 8px, 20px at opacities 0.12, 0.10, 0.08) keeps a sharp contact edge while the outer glow fades, which reads as real elevation.

Reading border-radius values correctly

The shorthand border-radius accepts one to four values, and they map to corners clockwise starting top-left: top-left, top-right, bottom-right, bottom-left. So border-radius: 8px 20px 8px 20px rounds top-left and bottom-right by 8px and the other two by 20px.

Each corner is an ellipse quarter, not always a circle. A slash gives the horizontal and vertical radii separately: border-radius: 40px / 20px makes every corner an ellipse 40px wide and 20px tall. The browser also enforces a limit: if the sum of two radii on one edge exceeds that edge's length, all radii scale down by the same factor so they fit. That is why a 100px radius on a 60px-tall button becomes exactly 30px, half the height, producing a pill.

To make a perfect circle, set the element to equal width and height and use border-radius: 50%. The percentage is relative to each axis, so on a non-square box 50% gives an ellipse, not a circle.

Common mistakes

Confusing gradient angle direction. CSS 0deg points up and increases clockwise. Many people expect 0deg to point right, as in math. Check: 90deg should flow left to right.

Relying on default color positions. If you omit stop positions, the browser spaces stops evenly. Four colors land at 0%, 33.3%, 66.7% and 100%. If you want a hard color band, set two stops to the same position, for example red 50%, blue 50%.

Spread on the wrong sign. A negative spread shrinks the shadow, useful for a shadow that peeks out only on one side. A positive spread grows it in every direction before blur applies, which can leak past rounded corners.

Forgetting inset. Adding the inset keyword draws the shadow inside the box, which is how you carve a pressed-button or inner-glow effect. Without it the shadow sits outside.

Related tools

These pages pair well with visual CSS work. Convert and contrast-check your gradient colors with the Color Converter & Contrast Checker before you commit them. When you build a demo page and inspect its assets, the MIME Type Lookup confirms how images and fonts are served, and the User-Agent Parser helps you reason about which browsers your visitors run.

Frequently asked questions

Do I need vendor prefixes like -webkit-gradient?

No. Every current browser supports unprefixed linear-gradient, radial-gradient, conic-gradient, box-shadow and border-radius. The old -webkit-gradient() function used a different syntax and has been unnecessary since around 2013.

Why does my gradient look muddy in the middle?

sRGB interpolation can pass through a gray-brown midpoint when you blend complementary colors, for example blue to yellow. Add in oklch after the angle to interpolate in a perceptual space, which keeps the midpoint bright.

Can one element have several shadows and a gradient at once?

Yes. box-shadow takes a comma-separated list of any length, and background can stack multiple gradients, also comma-separated, with the first one drawn on top.

How many color stops can a gradient have?

The spec sets no fixed limit, and browsers accept dozens. In practice two to four stops cover most designs; more than six is usually a sign you want an image instead.

Why did my huge border-radius stop growing?

The browser clamps each corner so opposite radii on an edge never exceed that edge's length. Once a radius reaches half the shorter side, the corner is already a full semicircle, and larger values change nothing.