콘텐츠로 이동
Study Noteshadcn/ui

5. 형태 리소스

색을 바꾸면 “다른 색”이 되지만, 형태를 바꾸면 “다른 회사 제품”이 된다.

이 장에서 처음 나오는 말4개
radiusBorder Radius
모서리 둥글기. shadcn/ui는 --radius 하나를 정하면 나머지 크기가 계산으로 따라오게 만든다.
스케일Scale
값을 아무렇게나 쓰지 않고 정해진 단계로만 쓰는 것. 간격을 4·8·12·16px로만 쓰면 화면이 정돈된다.
파생Derived
기준값 하나에서 계산으로 뽑아내는 것. --radius-sm: calc(var(--radius) * 0.6) 처럼.
고도Elevation
요소가 얼마나 떠 있어 보이는가. 그림자 세기로 표현한다. 모달 > 드롭다운 > 카드 > 바탕 순.

--radius — 하나에서 전부 나온다

섹션 제목: “--radius — 하나에서 전부 나온다”

shadcn/ui가 globals.css에 넣어 주는 것 중 색 다음으로 중요한 게 이 한 줄이다.

:root {
--radius: 0.625rem; /* 10px */
}
@theme inline {
--radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.4);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
}

컴포넌트는 rounded-md, rounded-lg만 쓴다. 그래서 --radius 한 줄을 바꾸면 버튼·카드·입력창·모달이 전부 같이 움직인다.

rounded-none
rounded-sm
rounded
rounded-md
rounded-lg
rounded-xl
rounded-2xl
rounded-full

같은 마크업을 --radius만 바꿔 렌더한 것이다.

--radius: 0.125rem
로그인
계정으로 계속하기
--radius: 0.625rem
로그인
계정으로 계속하기
--radius: 1.25rem
로그인
계정으로 계속하기
  • 왼쪽 — 각지다. 금융·엔터프라이즈·관리자 도구의 인상
  • 가운데 — shadcn 기본값. 요즘 SaaS의 표준적인 느낌
  • 오른쪽 — Material Design. 친근하고 모바일 앱스러움

색도 폰트도 같이 바뀐 프리셋이지만, 모서리만 따라가며 봐도 인상 차이의 절반 이상이 여기서 온다.

--radius-sm: 4px; --radius-lg: 12px; 처럼 따로 적으면 안 되나? 된다. 하지만 —

--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 10px;
--radius-xl: 14px;

“전체적으로 더 각지게” → 네 줄을 각각 계산해서 고친다. 비율이 어긋나면 큰 요소만 유난히 둥글어 보인다.

“결정은 하나, 값은 여러 개” — 이게 파생의 요점이다.

Tailwind 4는 간격도 기준값 하나에서 파생시킨다.

@theme {
--spacing: 0.25rem; /* = 4px, 기본값 */
}

p-1 = 4px, p-2 = 8px, p-4 = 16px처럼 번호가 기준값에서 계산된다. p-0.5 같은 반 단계와 p-px 같은 예외도 있지만, 한 스케일을 공유한다는 점이 핵심이다.

p-0.5
2px
p-1
4px
p-2
8px
p-3
12px
p-4
16px
p-6
24px
p-8
32px
p-12
48px
p-16
64px
p-24
96px

스케일 없이 쓰면 p-[13px], mt-[7px], gap-[18px] 같은 값이 섞인다. 개별적으로는 아무 문제 없어 보이는데, 화면 전체로 보면 정렬이 미묘하게 어긋난다.

  • 사람 눈은 4px 단위의 규칙성을 인식한다. 13px과 12px 중 12px이 “정돈돼” 보인다
  • 값이 정해져 있으면 논쟁이 사라진다. “여기 여백 몇이죠?” → “gap-4”
  • 나중에 전체 밀도를 조절할 때 --spacing만 건드리면 된다

관리자 화면처럼 정보를 빽빽하게 넣어야 하면 --spacing을 줄인다.

:root { --spacing: 0.25rem; } /* 4px — 기본 */
.dense { --spacing: 0.2rem; } /* 3.2px — 화면당 20% 더 담긴다 */

p-4가 16px에서 12.8px이 된다. 클래스는 그대로인데 밀도만 바뀐다.

테두리는 색 토큰(4장)과 겹치지만, 형태 관점에서 볼 게 하나 있다.

토큰쓰이는 곳
--border카드·구분선 등 일반 테두리
--input입력창 테두리 — 일반 테두리보다 진하게 두는 경우가 많다
--ring포커스 링 — 키보드로 이동했을 때 나오는 테두리

--ring이 왜 따로 있나? 포커스 표시는 접근성 필수 요소다. 키보드만 쓰는 사람에게는 “지금 어디에 있는지”를 알려주는 유일한 단서라 배경과 확실히 구분되는 색이어야 한다. 그래서 일반 테두리와 값을 분리한다.

그림자는 장식이 아니라 “이게 저것보다 위에 떠 있다”는 정보다.

shadow-sm
shadow
shadow-md
shadow-lg
shadow-xl
층그림자예
바탕없음페이지 배경
살짝 뜸shadow-sm카드, 버튼
떠 있음shadow-md드롭다운, 팝오버
확실히 위shadow-lg모달, 시트

순서를 지키는 게 규칙의 전부다. 모달이 카드보다 그림자가 약하면 층위가 뒤집혀 보인다.

radius·spacing·border·shadow 네 토큰이 각각 어떤 유틸리티 클래스로 파생되는지 짝지은 그림
  • --radius 한 줄이 앱 전체 인상의 절반을 결정한다. 나머지 크기는 계산으로 파생된다
  • 각지면 엔터프라이즈, 둥글면 친근함 — 브랜드 성격을 가장 싸게 표현하는 수단
  • 간격은 --spacing 기준의 스케일로만 쓴다. p-[13px]가 늘면 스케일이 무너지는 신호
  • 밀도 조절은 --spacing 하나로 — 클래스는 그대로 두고 화면 밀도만 바꾼다
  • --ring은 접근성 요소다. outline: none으로 지우지 않는다
  • 그림자는 고도 정보다. 순서(카드 < 드롭다운 < 모달)만 지키면 된다
  • 다크 모드에서는 검은 그림자만으로 부족하다. 표면의 밝기 차이도 함께 쓴다