DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

border-radius Is More Powerful Than You Think

Most developers use border-radius with a single value. border-radius: 8px for cards, border-radius: 50% for circles, maybe border-radius: 9999px for pill-shaped buttons. That covers 90% of use cases. But the property accepts up to eight values, and the shapes you can create with the full syntax are surprisingly versatile.

Let me show you what the full specification actually allows.

The shorthand is hiding complexity

The border-radius property is shorthand for four individual properties:

border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px;
Enter fullscreen mode Exit fullscreen mode

Each of these individual properties accepts two values: a horizontal radius and a vertical radius. When they're different, the corner becomes an elliptical arc instead of a circular one.

/* Circular corner: 10px radius */
border-top-left-radius: 10px;

/* Elliptical corner: 20px wide, 10px tall */
border-top-left-radius: 20px 10px;
Enter fullscreen mode Exit fullscreen mode

The full shorthand uses a slash to separate horizontal and vertical radii:

/* All corners: 20px horizontal, 10px vertical */
border-radius: 20px / 10px;

/* Each corner different, horizontal / vertical */
border-radius: 10px 20px 30px 40px / 5px 10px 15px 20px;
Enter fullscreen mode Exit fullscreen mode

Before that slash, you're setting the horizontal radius for each of the four corners (top-left, top-right, bottom-right, bottom-left, following the standard CSS clockwise order). After the slash, the vertical radii in the same order.

Organic shapes with eight values

The slash syntax is the key to creating shapes that don't look like they were made with a compass and straightedge. By varying horizontal and vertical radii independently across all four corners, you can create organic, blob-like shapes:

/* Organic blob shape */
.blob {
  border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
  width: 200px;
  height: 200px;
  background: #6C5CE7;
}
Enter fullscreen mode Exit fullscreen mode

This produces a shape that looks like a smooth stone or a melted circle. It's the same technique behind the "blob" shapes that have become popular in modern web design. No SVG needed, no clip-path, just border-radius with asymmetric values.

You can animate these values for a morphing effect:

@keyframes morph {
  0%   { border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; }
  50%  { border-radius: 30% 60% 70% 40% / 50% 60% 30% 60%; }
  100% { border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; }
}

.blob {
  animation: morph 8s ease-in-out infinite;
}
Enter fullscreen mode Exit fullscreen mode

This creates a constantly shifting organic shape, which makes for compelling hero section backgrounds or decorative elements.

Percentage vs pixel values

Percentages and pixels behave differently, and mixing them can produce unexpected results.

Pixel values create corners with a fixed radius. A border-radius: 20px corner looks the same regardless of the element's size.

Percentage values are relative to the element's dimensions. border-radius: 50% creates a circle only when the element is square. On a rectangle, it creates an ellipse. border-radius: 50% actually means "the horizontal radius is 50% of the element's width, and the vertical radius is 50% of the element's height."

/* This is a circle (square element) */
.circle {
  width: 100px;
  height: 100px;
  border-radius: 50%;
}

/* This is an ellipse (rectangular element) */
.ellipse {
  width: 200px;
  height: 100px;
  border-radius: 50%;
}
Enter fullscreen mode Exit fullscreen mode

For pill-shaped buttons where the height varies, use a large pixel value rather than 50%:

/* Works regardless of height */
.pill {
  border-radius: 9999px;
}

/* 50% would create an ellipse on non-square elements */
Enter fullscreen mode Exit fullscreen mode

The corner overlap rule

What happens when your border-radius values are too large for the element? If two adjacent corners overlap, the browser proportionally reduces all radii until they fit. This is why border-radius: 9999px works for pills -- the browser sees that 9999px is far larger than half the element's dimension and scales it down to the maximum that fits, which is half the shorter side.

This is defined in the spec as "corner curves must not overlap." It means you can be generous with your radius values and the browser will handle the constraint resolution.

Practical patterns

Ticket or coupon shape:

.ticket {
  border-radius: 8px;
  position: relative;
}

.ticket::before,
.ticket::after {
  content: '';
  position: absolute;
  width: 20px;
  height: 20px;
  background: white; /* match page background */
  border-radius: 50%;
  top: 50%;
  transform: translateY(-50%);
}

.ticket::before { left: -10px; }
.ticket::after { right: -10px; }
Enter fullscreen mode Exit fullscreen mode

Top-only rounding (tabs, top cards):

.tab {
  border-radius: 8px 8px 0 0;
}
Enter fullscreen mode Exit fullscreen mode

Asymmetric card (one side rounded):

.card-left {
  border-radius: 12px 0 0 12px;
}
Enter fullscreen mode Exit fullscreen mode

Superellipse approximation:

iOS icons use a superellipse (squircle), not a simple rounded rectangle. CSS border-radius can't perfectly replicate a superellipse, but you can get close:

.squircle {
  border-radius: 22%;
  /* For a closer match, use clip-path with an SVG path */
}
Enter fullscreen mode Exit fullscreen mode

True squircles require clip-path or an SVG mask, but 22% radius on a square element is a reasonable approximation for most UI work.

Common mistakes

  1. Using border-radius: 50% for avatar circles without ensuring the image is square. If the source image has a different aspect ratio and you're using object-fit: cover, the border-radius still works. But if the container itself isn't square, you get an ellipse.

  2. Forgetting that overflow: hidden is needed for images. border-radius clips the element's background and border, but child content (like an <img> tag) overflows by default. Add overflow: hidden to the container.

  3. Inconsistent radius across a design system. Pick a scale and stick to it. Common scales are 2px, 4px, 8px, 12px, 16px, 24px (doubling progression) or 4px, 6px, 8px, 12px, 16px (smaller steps for subtle differences).

  4. Not accounting for borders. border-radius applies to the outer edge of the border. The inner edge's radius is border-radius - border-width. A 1px border with 4px radius creates a 3px inner radius. If the border is thick and the radius is small, the inside corners can appear sharp even though the outside is rounded.

  5. Animation performance. Animating border-radius causes repaints. For smooth animations, prefer transforms and opacity when possible. When you must animate border-radius (like the blob morph above), ensure the element has will-change: border-radius and test on lower-end devices.

For visually experimenting with all eight values and seeing the resulting shape in real time, I built a border radius generator at zovo.one/free-tools/border-radius-generator that lets you drag corners independently and copy the CSS.

border-radius is one of those CSS properties where the basic usage is trivial but the full power is hidden behind a syntax most people never explore. Eight values, a slash, and you have an organic shape generator built into every browser.


I'm Michael Lip. I build free developer tools at zovo.one. 350+ tools, all private, all free.

Top comments (0)