AniUI Academy

Shadows, Borders and Gradients

border-radius including elliptical corners and pill/circle shortcuts, box-shadow syntax with inset and stacked shadows, radial-gradient(), and text-shadow.

8 min read

Flat rectangles with sharp corners are the default. A small set of properties is responsible for almost every piece of polish that makes an interface look deliberately designed rather than merely functional — rounded corners, soft depth, a glow, a radiating background.

border-radius

The basic case rounds all four corners equally:

.card {
  border-radius: 12px;
}

Two long-standing shortcut patterns come up constantly:

.pill   { border-radius: 9999px; } /* any value larger than half the height works */
.circle { border-radius: 50%; width: 60px; height: 60px; }

border-radius: 9999px on an element with a fixed height rounds the two ends into a full pill/stadium shape, because the radius is clamped to whatever the actual geometry allows — you don't need to calculate half the element's height by hand. border-radius: 50% on a perfectly square element (equal width and height) produces a true circle, since a 50% radius rounds each corner all the way to the center of its adjacent edge.

A less common but useful trick: each corner can take two values, separated by a slash — the first controls the corner's horizontal radius, the second its vertical radius, producing an elliptical rather than circular corner:

.leaf-shape {
  border-radius: 50px / 20px;
}

This rounds every corner with a wide, shallow ellipse (50px across, 20px tall) rather than a uniform circular curve — useful for organic, non-uniform shapes that a single-value border-radius can't produce.

box-shadow

box-shadow draws a shadow around an element's box. The full syntax is offset-x offset-y blur-radius spread-radius color:

.card {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

Reading each value:

  • offset-x — horizontal shift. 0 keeps the shadow centered left-right.
  • offset-y — vertical shift. Positive pushes it downward, which is the common "light source above" look.
  • blur-radius — how soft the shadow's edge is. 0 gives a hard-edged shadow; larger values feather it out.
  • spread-radius (optional) — grows or shrinks the shadow's shape before blurring, independent of the offset.
  • color — usually a low-opacity black or the surface's own darkened tone, since a fully opaque shadow tends to look harsh.

Adding the inset keyword flips the shadow to draw inside the element's border instead of outside it — useful for a pressed-in, recessed look:

.input-pressed {
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2);
}

You can stack multiple shadows on one element by separating them with commas, which lets you build up a more realistic, layered depth effect than one shadow alone usually achieves:

.elevated-card {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.08),
    0 4px 12px rgba(0, 0, 0, 0.10),
    0 12px 24px rgba(0, 0, 0, 0.08);
}

Each shadow in the list is drawn independently, closest-to-the-element first; combining a tight, subtle shadow with a larger, softer one tends to read as more natural depth than a single broad shadow.

radial-gradient()

You've already met linear-gradient() for straight-line color transitions. radial-gradient() works the same way but radiates outward from a center point instead of along a line:

.spotlight {
  background-image: radial-gradient(circle, #fef08a, #f97316);
}

The same color-stop syntax from linear-gradient() applies — you can add as many stops as you like, and pin them to specific positions:

.glow {
  background-image: radial-gradient(
    circle at top left,
    rgba(59, 130, 246, 0.4) 0%,
    transparent 70%
  );
}

circle at top left moves the gradient's center away from the default (the element's own center) to a specific corner — useful for a soft directional glow rather than a centered spotlight.

text-shadow

text-shadow uses the exact same offset/blur/color syntax as box-shadow (minus spread-radius and inset, neither of which apply to text), but draws the shadow behind the glyphs of the text itself rather than around an element's box:

.hero-heading {
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

Like box-shadow, multiple comma-separated shadows stack — a common trick for a subtle outline effect is two or more offset shadows in different directions layered on the same text.

Try it yourself

Try it yourself
Loading playground...

What to remember

  • border-radius rounds all four corners; 9999px makes a pill, 50% on a square makes a circle, and a slash (50px / 20px) rounds a corner elliptically.
  • box-shadow: offset-x offset-y blur-radius spread-radius color, with inset for a recessed look; comma-separate multiple shadows to stack them for realistic depth.
  • radial-gradient() uses the same color-stop syntax as linear-gradient() but radiates outward from a center point instead of along a line.
  • text-shadow uses the same offset/blur/color syntax as box-shadow, applied to the text itself rather than the element's box.