CSS Border Radius: Elliptical Corners, Squircles, and Blob Shapes
Most engineers stop at border-radius: 12px and move on. The full grammar of the property accepts eight values, supports elliptical corners, and powers the entire blob-shape trend. Knowing the rest of it makes the difference between a card that looks like every other card and a brand mark you can actually reproduce in CSS without resorting to SVG masks.
I went years writing only the one-value shorthand. The day I had to recreate an iOS-style squircle I realized none of the syntax I knew would get me there. It turns out the property had been quietly hiding the answer in its second half the whole time.
The eight values most people never see
The full border-radius shorthand looks like this:
/* 8개 값 표기 — 슬래시 앞은 가로, 뒤는 세로 반지름 */
border-radius: 10px 20px 30px 40px / 5px 15px 25px 35px;
/* 순서는 모두 top-left → top-right → bottom-right → bottom-left */
/* 슬래시가 없으면 가로 = 세로로 간주됨 */Each corner gets two radii: one along the horizontal axis, one along the vertical. When the two are equal you get a quarter circle. When they differ you get a quarter ellipse. The browser draws the curve between the two radii.
The shorthand fans out like a clock starting at the top-left. The single-value form 12px means all four corners get a 12px circular radius. Three values mean top-left, top-right + bottom-left, bottom-right — which trips up engineers expecting clockwise order.
Elliptical corners change the curve itself
Splitting horizontal and vertical with a slash unlocks shapes a circular radius cannot reach:
/* 정사각형 요소에서 완벽한 원 */
.circle { border-radius: 50%; }
/* 가로로 길쭉한 알약 */
.pill { border-radius: 9999px; }
/* 가로 50%, 세로 25% — 가로로 더 둥근 타원 */
.ellipse { border-radius: 50% / 25%; }
/* 한쪽 코너만 늘린 비대칭 */
.leaf { border-radius: 50% 0 50% 0; }Use percent for shapes that need to scale with the element — pills, circles, blob avatars. Use pixels when you want the same visual radius regardless of element size, which is almost every card and button.
A common confusion: 9999px on a 200px-tall element clamps to half the shortest side. So setting border-radius: 9999px gives the same visual result as 100pxon that element. The browser will not draw past the element's edge.
The iOS squircle, approximately
A true squircle is a superellipse with an exponent around 5, and CSS cannot draw one directly. What CSS can draw is a close approximation by combining a generous border-radius with a subtle horizontal-vertical split that pushes the curve slightly outward.
/* 200x200 박스용 의사 squircle */
.squircle {
width: 200px;
height: 200px;
border-radius: 30% / 50%;
}
/* 더 정확하려면 SVG path 또는 mask-image 사용 */
.squircle-real {
mask-image: url('data:image/svg+xml,...');
}The trick is the asymmetric percentages. A horizontal radius smaller than the vertical radius squeezes the curve toward the corners and gives the soft-square look Apple uses for app icons. Push the percentages further apart and you start sliding into blob territory.
Blobs come from asymmetric corners
Designers picked up blob shapes around 2019 and they have not gone away. CSS produces passable blobs by giving each corner a different combination of horizontal and vertical radii:
.blob {
width: 240px;
height: 240px;
border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
background: linear-gradient(135deg, #a78bfa, #38bdf8);
}
/* 변형: 코너마다 다른 비율 → 자연스러운 유기체 형태 */
.blob-alt {
border-radius: 63% 37% 54% 46% / 55% 48% 52% 45%;
}For real motion-graphic blobs, animate the radius values themselves. CSS @keyframes can morph between two valid radius sets and the browser interpolates each value, which produces a slow organic flow without needing JavaScript.
Tuning these by eye is tedious. The border-radius generator gives sliders for each corner and a live preview, which is faster than guessing percentages.
The overflow trap that breaks every other rounded card
The most common bug with border-radius is child content rendering past the rounded edge. It looks fine when the card is empty and breaks the moment an image or absolutely positioned element sits inside.
/* 문제: 자식 이미지가 둥근 모서리 밖으로 삐져나옴 */
.card {
border-radius: 16px;
}
/* 해결: overflow: hidden — 자식을 모서리에 맞춰 잘라냄 */
.card {
border-radius: 16px;
overflow: hidden;
}
/* 단, position: absolute 자식은 overflow를 무시할 수 있으니 */
/* 컨테이너에 isolation 또는 transform 추가가 필요할 수도 있음 */
.card-isolated {
border-radius: 16px;
overflow: hidden;
isolation: isolate;
}Safari historically had a long-running bug where overflow: hidden on a rounded parent failed to clip a child during a transform animation. The workaround is transform: translateZ(0) on the parent to force a stacking context. Newer Safari versions ship the fix, but the workaround is harmless on every browser.
When to reach for clip-path instead
Border-radius is limited to four corners with two radii each. Anything more complex — a notched bottom edge, a tab shape, a custom polygon — needs clip-path or SVG.
- Reach for border-radius when the corner is a clean arc or ellipse and the rest of the shape is rectangular.
- Reach for clip-path when you need polygons, notches, or per-vertex control.
- Reach for SVG when the shape needs strokes, gradients along the outline, or animation along a path.
Border-radius is the cheapest of the three. It anti-aliases on the GPU, animates smoothly, and the browser handles all the math. Use it whenever the shape allows.
Animating border-radius cleanly
Border-radius interpolates per-value. Going from a sharp square (0) to a circle (50%) works out of the box and is the cheapest possible CSS animation on modern GPUs.
@keyframes morph {
0%, 100% {
border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
}
50% {
border-radius: 60% 40% 50% 50% / 70% 50% 50% 30%;
}
}
.shape {
animation: morph 18s ease-in-out infinite;
}Hover transitions go the other direction — square buttons that round into pills on focus, avatars that pulse a hair larger on hover. Pair the radius animation with a tiny shadow change from the box-shadow generator and the interaction feels physical without spending more than four lines of CSS.
Browser inconsistencies you can actually feel
The spec is the same in every browser, but the render is not. Three differences worth knowing about:
- Safari anti-aliasing — Safari draws border-radius corners with a slightly softer anti-alias than Chromium. The same
12pxcorner looks fractionally rounder on macOS than on Linux Chrome. Not enough to ship a per-browser override, but worth knowing during a pixel-perfect QA pass. - The overflow-clip-margin gotcha— Chromium expanded the area the rounded clip applies to in 2022, which silently changed how some absolutely positioned children render inside rounded parents. Safari followed in 2023. Older Firefox versions (pre-118) still clip strictly to the radius. If a design looks "off" only in one browser, this is the first thing to check.
- Border-radius on table-cell elements — Chromium ignores border-radius on
display: table-celleven though the spec allows it. Safari respects it. Workaround: wrap the cell content in a div with the radius, or switch the parent todisplay: grid.
Performance — when border-radius costs anything
Border-radius is one of the cheapest CSS properties on a modern GPU. The compositor handles the rounded edge with anti-aliasing, and animating between two radius values runs at 60fps without breaking a sweat on hardware from the last decade.
The cost shows up in two narrow cases:
/* 1. overflow: hidden + border-radius + large child = repaint */
.card {
border-radius: 16px;
overflow: hidden;
}
.card img {
width: 100%;
/* 카드가 스크롤될 때마다 클리핑 영역 재계산 — Safari에서 특히 비쌈 */
}
/* 해결: will-change를 부모에 — 컴포지터 레이어로 승격 */
.card {
border-radius: 16px;
overflow: hidden;
will-change: transform;
}
/* 2. 거대한 box-shadow + border-radius + 스크롤 */
.card {
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0,0,0,0.2);
/* shadow blur가 corner radius와 만나면 paint가 무거워짐 */
}
/* 가능하면 작은 shadow + filter: drop-shadow()로 대체 */For 99% of cards, buttons, and avatars the cost is rounding to zero. The two cases above only become measurable when there are hundreds of rounded elements scrolling at once (think infinite feed UIs, large dashboards). Profile before optimizing.
Storing radius values as design tokens
Hard-coding 12pxin twenty components is the bug that ages worst. The first time the design system says "let's make everything 4px more rounded" you discover that half the components used 12px and half used 14px. A token system fixes this once.
/* 디자인 토큰 — CSS custom property로 노출 */
:root {
--radius-xs: 4px; /* 칩, 작은 배지 */
--radius-sm: 8px; /* 인풋, 버튼 */
--radius-md: 12px; /* 카드 */
--radius-lg: 16px; /* 큰 카드, 모달 */
--radius-full: 9999px;/* 알약, 아바타 */
}
/* 컴포넌트는 토큰만 참조 */
.card { border-radius: var(--radius-md); }
.button { border-radius: var(--radius-sm); }
/* Tailwind 사용 시 — tailwind.config.ts에 매핑 */
// theme.extend.borderRadius = {
// xs: '4px', sm: '8px', md: '12px', lg: '16px', full: '9999px'
// }Five tokens cover most design systems. More than seven and the team stops remembering which is which; fewer than four and the visual rhythm flattens. Avoid stepless or free-form radius values in production code — they invariably drift.
Wrapping up
Border-radius gets fancy at exactly two moments: when you split horizontal and vertical with a slash, and when you give each corner its own pair of values. Everything else follows from there — squircles, blobs, asymmetric leaf shapes, motion graphics on a CSS budget.
Once the shape feels right in the generator, copy the value and treat it like any other design token. Spending two minutes on the corners pays back every time someone glances at the card.
Related Tools
Related Articles
How to Generate Secure Passwords in 2026: A Complete Guide
Credential attacks now lean on GPU clusters and ML pattern guessing. What entropy, length, and randomness actually buy you, plus the password manager picks that hold up in 2026.
2025-12-15 · 8 min readData FormatsJSON vs YAML: When to Use What — A Developer's Guide
JSON wins on APIs; YAML wins on configs. Side-by-side syntax, parser behaviour, and where each fits across Kubernetes manifests, REST payloads, and GitHub Actions.
2025-12-28 · 10 min read