Refactoring UI
비주얼 디자인은 재능이 아닙니다. 한 번만 결정하면 되는 소수의 체계적인 결정과 계층을 만드는 소수의 기술로 구성됩니다. 이 스킬이 바로 그 체계와 기술입니다.
아마추어처럼 보이는 UI의 가장 큰 원인은 값을 임의로 선택하는 것입니다. 여기서 17px, 저기서 #3B82F6, 호버 상태를 위해 lighten(5%)와 같이 말이죠. 항상 스케일을 기반으로 디자인하세요.
체계 — 이것들을 사용하고, 다시 유도하지 마세요
이 목록에서 선택하세요. 목록에 없는 값은 절대 발명하지 마세요.
간격과 크기
16px을 기준으로, 그 요소와 배수로 구성:
4 8 12 16 24 32 48 64 96 128 192 256 384 512 640 768
작은 쪽에서는 촘촘하고, 큰 쪽으로 갈수록 넓어집니다. 인접한 두 값은 약 25% 이상 차이가 나면 안 됩니다 — 그래야 선택이 명확해집니다. "4의 배수"와 같은 선형 스케일은 실패합니다: 120px과 124px 사이에서 결정하는 데 도움이 되지 않습니다.
마진, 패딩, 너비, 높이, 아이콘 크기, 테두리 너비 등 모든 공간적 요소에 사용하세요. 비활성화 상태, 오버레이 및 호버 틴트를 위해 불투명도 값도 소수 집합(예: .05 .1 .2 .4 .6 .8)으로 고정하세요. 매번 슬라이더를 눈대중으로 맞추지 마세요. 다른 스케일과 동일한 논리입니다: 한 번 결정하고, 모든 곳에 재사용하세요.
타이포그래피 스케일
12 14 16 18 20 24 30 36 48 60 72
비율(4:5, 2:3, 황금비)로 구축된 모듈식 스케일이 아닙니다. 그런 스케일은 브라우저 간에 일관되지 않게 반올림되는 분수 픽셀 값을 생성하고 인터페이스 밀도에 비해 너무 드물기 때문에, 직접 고른 값(느낌에 따라 선택됨)이 더 낫습니다.
단위: px 또는 rem만 사용하세요. 절대 em을 사용하지 마세요. em은 현재 글꼴 크기에 상대적이므로, 1.25em 부모 내부의 .875em은 17.5px로 계산됩니다 — 스케일에 없는 값입니다. 스케일이 조용히 사라집니다.
글꼴 굵기
두 가지 굵기면 충분합니다:
- 400 또는 500 — 본문 및 대부분의 UI 텍스트
- 600 또는 700 — 강조된 모든 것
UI에서는 400 미만은 사용하지 마세요. 강조를 낮추려면 더 밝은 색상이나 더 작은 크기를 사용하세요 — 절대 더 가벼운 굵기를 사용하지 마세요.
색상
5-스와치 팔레트 생성기가 제공하는 것보다 훨씬 더 많은 색상이 필요합니다.
- 회색: 8–10 단계. UI의 거의 모든 것은 회색입니다 — 텍스트, 배경, 패널, 테두리, 양식 컨트롤. 3~4단계로는 항상 부족합니다. 순수한 검정(진정한 검정은 부자연스러워 보입니다)이 아닌 매우 어두운 회색에서 시작하세요.
- 주 색상: 5–10 단계, 하나 또는 두 개의 주 색상.
- 강조 색상: 각각 5–10 단계 — 위험을 나타내는 빨간색, 경고 노란색, 긍정적인 녹색, 그리고 제품이 구별해야 하는 기타 모든 것(차트 시리즈, 캘린더 이벤트, 태그). 복잡한 UI의 경우 10가지 색상 × 5–10 단계가 일반적입니다.
100(가장 밝음) → 900(가장 어두움)으로 이름을 지정하고, 기본 500으로 설정합니다.
다음 순서로 스케일을 구축하세요: 500을 먼저 선택합니다(주/강조 색상의 경우 버튼 배경으로 작동하는 음영이어야 함). 그런 다음 가장자리를 찾습니다 — 900은 일반적으로 텍스트 색상이고, 100은 배경 틴트입니다. 알림 컴포넌트는 둘 다 사용하므로 하나를 디자인하고 두 값을 읽어옵니다. 그런 다음 700과 300을 이웃 간의 완벽한 절충으로 채우고, 같은 방식으로 800 600 400 200을 채웁니다.
색상은 16진수가 아닌 HSL로 작성하세요. hsl(220, 95%, 34%)와 hsl(220, 65%, 61%)는 시각적으로 관련되어 있지만, #03369E와 #507DD7는 그렇지 않습니다.
런타임에 lighten() / darken()으로 음영을 생성하지 마세요. 그렇게 하면 35개의 약간 다른 파란색이 생깁니다.
그림자 — 다섯 가지 높이
0 1px 3px hsla(0,0%,0%,.2) /* 거의 떠 있지 않음 — 버튼 */
0 4px 6px hsla(0,0%,0%,.2) /* 드롭다운 */
0 5px 15px hsla(0,0%,0%,.2)
0 10px 24px hsla(0,0%,0%,.2)
0 15px 35px hsla(0,0%,0%,.2) /* 모달 */
선택은 *이것이 z-축에서 어디에 위치하는가?*에 기반해야 하며, *어떤 그림자가 예뻐 보이는가?*가 아닙니다. 사용자에게 더 가까울수록 더 많은 주의를 받습니다. :active에서 버튼의 그림자를 줄이면 눌린 느낌을 줍니다. 드래그 재정렬을 위해 선택된 목록 항목의 그림자를 키우면 반대 효과가 나타납니다 — "이제 형제 위에 있다"고 읽히며 드래그 어포던스 자체의 역할을 합니다.
이 다섯 가지는 기본값이며 모든 곳에서 괜찮습니다. references/techniques.md는 동일한 스케일의 정제된 두 부분 버전을 제공합니다 — 평행하지만 동일하지 않은 값입니다(최상위 단계가 더 무겁습니다). 디자인에서 그림자가 두드러질 때 이 버전을 사용하고, 그렇지 않을 때는 기본 버전을 사용하세요. 한 프로젝트에서 두 버전을 혼합하지 마세요.
줄 높이와 줄 길이
줄 높이는 글꼴 크기에 반비례하고 줄 너비에 비례합니다:
- 작은 텍스트 / 넓은 열 →
1.5~2 - 큰 제목 →
1이면 충분합니다.
줄 길이: 45–75자, 즉 max-width: 20em–35em입니다. 이는 주변 컨테이너가 더 넓은 경우에도 단락에 적용됩니다 — 하나의 콘텐츠 영역에서 혼합된 너비는 덜 정돈된 것이 아니라 더 세련되어 보입니다.
(em은 여기서 올바릅니다 — 측정값은 감싸는 텍스트와 함께 확장되어야 합니다. "절대 em 안 됨" 규칙은 타이포그래피 스케일에 한정되며, 여기서 em은 중첩을 통해 복합됩니다. 이것을 "수정"하지 마세요.)
테두리 반경
하나를 선택하고 일관성을 유지하세요. 작은 반경 = 중립적입니다. 큰 반경 = 장난기입니다. 없음 = 진지함/격식입니다. 하나의 인터페이스에서 사각형과 둥근 모서리를 섞으면 항상 더 나빠 보입니다.
절차
1. 레이아웃이 아닌 기능으로 시작하세요. "앱"을 디자인하지 마세요 — 제품에 무엇이 있는지 알기 전에 상단 탐색과 사이드바 중에서 결정할 수 없습니다. 하나의 실제 기능(검색 양식, 메시지 작성기)을 디자인하고, 껍데기가 나타나도록 두세요.
2. 세부 사항은 나중에. 초기에는 서체, 그림자 및 아이콘을 무시하세요. 먼저 회색조로 작업하세요 — 색상 대신 간격, 대비 및 크기에서 계층 구조를 강제합니다. 레이아웃이 작동하면 색상을 추가하세요.
3. 낮은 충실도에 과도하게 투자하지 마세요. 스케치, 와이어프레임 및 목업은 일회용입니다 — 아무도 앱의 정적 사진을 사용할 수 없습니다. 아이디어를 탐색하기 위해 존재합니다. 결정이 내려지면 버리고 실제 제품을 구축하세요.
4. 가장 작은 유용한 버전을 디자인하고, 그런 다음 구축하세요. 짧은 디자인→코드 주기로 작업하세요. 아직 제공할 준비가 되지 않은 기능을 암시하지 마세요 — 아직 배송할 수 없는 첨부 파일 영역이 있는 댓글 상자는 전체 기능을 차단합니다. 있으면 좋은 것은 나중에 디자인됩니다.
5. 제거를 통해 선택하세요. 스케일에서 값을 선택할 때: 옳다고 생각하는 값을 추측한 다음 양쪽에 있는 이웃과 비교하세요. 두 개는 분명히 틀릴 것입니다. 외부 옵션이 이기면, 그 값을 새로운 중간값으로 다시 비교를 실행하세요.
6. 너무 많은 흰색 공간으로 시작하여 제거하세요. 무언가가 나빠 보이지 않을 때까지 공간을 추가하면 최소값이 제공됩니다. 넉넉하게 시작하고 다듬으면 적절한 양이 제공됩니다. 밀집된 UI(대시보드)는 합법적입니다 — 하지만 기본값이 아니라 의도적인 결정으로서 말이죠.
7. 캔버스를 줄이세요. 1400px 아트보드에서 디자인된 작은 컴포넌트는 공간이 채워져 있기 때문에 종종 너무 넓어집니다. 약 400px에서 시작하여 먼저 모바일 레이아웃을 디자인하세요. 여기서 제약 조건은 실제입니다 — 그런 다음 큰 화면으로 가져와서 진정으로 비좁았던 부분만 완화하세요. 예상보다 덜 변경될 것입니다.
계층 구조 — 가장 많은 작업을 수행하는 기술
화면의 모든 것은 피라미드에 있습니다: 1차, 2차, 3차. 모든 것이 경쟁할 때 UI는 노이즈로 읽힙니다. 이것이 디자인을 "디자인된" 것처럼 보이게 만드는 것입니다 — 스타일링이 아닙니다.
크기가 전부는 아닙니다. 글꼴 크기에만 의존하면 너무 큰 기본 콘텐츠와 너무 작은 보조 콘텐츠가 생성됩니다. 대신 굵기와 색상을 사용하여 강조를 전달하고, 크기는 적절하게 유지하세요.
최대 세 가지 텍스트 색상:
- 어두운색 — 기본 콘텐츠
- 회색 — 보조 콘텐츠
- 더 밝은 회색 — 3차 콘텐츠(각주, 저작권)
세 가지 모두 실제 본문 크기 텍스트를 전달하므로, 모두 4.5:1이 필요합니다. "더 밝은 회색"은 여전히 이를 충족하는 가장 밝은 음영을 의미합니다 — 대략 9단계 램프의 중간이며, 창백한 쪽이 아닙니다. 창백한 음영은 비활성화된 상태와 큰 텍스트에만 사용됩니다.
강조를 낮춤으로써 강조하세요. 중요한 요소가 눈에 띄지 않고 추가할 것이 남아 있지 않을 때, 대신 경쟁하는 요소를 부드럽게 만드세요. 비활성 탐색 항목을 흐리게 처리하고, 사이드바의 배경색을 낮추어 기본 콘텐츠가 앞으로 나오도록 하세요.
작업: 의미론이 아닌 계층 구조별로 스타일을 지정하세요.
- 기본 → 채우기, 높은 대비. 일반적으로 페이지당 정확히 하나입니다.
- 보조 → 윤곽선, 또는 낮은 대비 배경.
- 3차 → 링크처럼 스타일을 지정합니다.
파괴적 ≠ 크고 빨간 버튼. "삭제"가 페이지의 기본 작업이 아니라면 3차 처리를 하세요 — 그런 다음 확인 대화 상자 내부에서 진정으로 기본 작업인 크고 빨간 기본 버튼으로 만드세요.
레이블은 최후의 수단입니다. label: value는 모든 데이터 조각에 동일한 가중치를 부여합니다. 대부분의 데이터는 형식($19.99, 이메일 주소)이나 컨텍스트를 통해 스스로 식별됩니다. 레이블이 진정으로 필요한 경우 값을 접으세요("재고: 12" 대신 "재고 12개 남음"), 또는 시각적으로 보조 콘텐츠로 추가하세요. 예외: 사용자가 레이블을 찾기 위해 스캔하는 사양 시트 스타일 페이지에서는 대신 레이블을 강조하세요.
굵기와 대비의 균형을 맞추세요. 솔리드 아이콘은 시각적으로 무겁고 옆에 있는 텍스트보다 더 크게 보일 것입니다 — 색상을 부드럽게 하여 보상하세요. 반대의 경우도 마찬가지입니다: 부드러운 색상에서 1px 테두리가 너무 미묘하지만 한 번 어둡게 하면 너무 거칠어질 때, 부드러운 색상을 유지하고 2px로 이동하세요. 낮은 대비를 수정하려면 굵기를 추가하고, 과도한 굵기를 수정하려면 대비를 줄이세요.
시각적 계층 구조 ≠ 문서 계층 구조. 의미론적 마크업과 시각적 가중치는 별개의 결정입니다. 섹션 제목은 일반적으로 제목이 아니라 레이블입니다 — 16px의 h1도 괜찮으며, 콘텐츠가 스스로 말해주기 때문에 제목을 시각적으로 완전히 숨겨야 하는 경우도 있습니다.
하드 룰
이것에서 벗어나면 특정하고 인식 가능한 실패가 발생합니다.
- 색상 배경에 회색 텍스트를 절대 사용하지 마세요. 회색-흰색은 대비를 줄이기 때문에 작동합니다. 색상에 회색은 더러워 보일 뿐입니다. 불투명도를 낮춘 흰색은 바래고 비활성화된 것처럼 보이며, 문자를 통해 패턴이 보입니다. 배경의 색조로 색상을 직접 선택하고, 채도와 명도를 조정하세요.
- 타이포그래피 스케일에
em을 절대 사용하지 마세요.px또는rem을 사용하세요. - 런타임에 음영을 절대 생성하지 마세요. 미리 정의하세요.
- 확장되지 않아야 하는 것에 백분율 너비를 절대 사용하지 마세요. 사이드바는 고정 너비를 받습니다. 기본 영역은 유연합니다. 요소는
max-width를 가지며 화면이 실제로 더 작을 때만 축소됩니다 — 로그인 카드는 큰 화면보다 중간 화면에서 더 넓어지면 안 됩니다. - 중단점에서 비례적으로 확장하지 마세요. 큰 요소는 작은 요소보다 더 빠르게 축소되어야 합니다. 14px 모바일 본문에 있는 2.5em 제목은 35px로 계산됩니다 — 너무 큽니다. 20-24px이어야 합니다. 마찬가지로 버튼의 패딩은 버튼이 축소됨에 따라 비례적으로 더 좁아져야 하며, 글꼴 크기와 함께 확장되지 않아야 합니다.
- 그룹 주위에는 그룹 내부보다 항상 더 많은 공간을 두세요. 이것은 "어떤 레이블이 어떤 필드에 속하는가", 좁은 글머리 기호 목록, 잘못된 단락에 연결된 것처럼 보이는 제목에 대한 수정 사항입니다. 모호한 간격은 기능적 버그이며, 단지 못생긴 것만은 아닙니다.
- 유일한 신호로 색상을 절대 사용하지 마세요. 아이콘, 모양 또는 텍스트 신호를 추가하세요. 차트의 경우, 색조보다는 대비(한 색상의 밝은→어두운 음영)로 시리즈를 구분하세요 — 색맹 사용자는 명도를 안정적으로 읽지만 색조는 그렇지 않습니다.
- 최소 대비: 일반 텍스트의 경우 4.5:1. 3:1 허용치는 큰 텍스트에만 적용되며, WCAG는 이를 24px 일반 또는 18.66px 굵은 텍스트로 정의합니다 — 18px이 아닙니다. 텍스트가 진정으로 그렇게 크지 않는 한 4.5:1을 가정하세요. 흰색-색상이 실패하면 반전시키세요: 밝은 색상 틴트에 어두운 색상 텍스트(
references/systems.md참조). 별도로, 3:1은 텍스트가 아닌 것에도 적용됩니다(WCAG 1.4.11): 테두리가 컨트롤(입력 윤곽선, 체크박스 가장자리)을 식별하는 유일한 것이라면, 배경에 대해 3:1이 필요합니다. 단지 콘텐츠를 나누는 얇은 선은 그렇지 않습니다. 이들은 두 개의 다른 토큰이며, 하나가 아닙니다. - 아이콘을 의도된 크기에서 멀리 확장하지 마세요. 48px에서 16-24px 아이콘은 투박하고 디테일이 부족해 보입니다. 대신 색상 원 안에 넣으세요.
참조
assets/tokens.css — 위의 모든 항목을 CSS 사용자 정의 속성으로 완전하고 대비가 확인된 시작 세트: 간격, 타입, 굵기, 테두리 너비, 고정 불투명도 스케일, 9단계 쿨 그레이 램프, 9단계 주 색상, 세 개의 강조 트리오, 다섯 개의 엘리베이션, 의미론적 역할 레이어(--surface, --text-primary, --action…) 및 해당 역할만 재정의하는 다크 모드 블록. 이것을 복사하고 이 글에서 스케일을 다시 유도하는 대신 색조를 재조정하세요. 원시 램프가 아닌 컴포넌트의 역할을 참조하세요 — 이것이 다크 모드를 작동하게 만드는 것입니다. 모든 텍스트/표면 쌍은 두 모드에서 ≥4.5:1로 확인되었고 모든 기능적 테두리는 ≥3:1입니다. 의도적인 하위 임계값 음영(비활성화됨, 장식용 구분선, 큰 텍스트 전용 단계)은 기준에 따라 제외되며 인라인으로 주석 처리됩니다.
작업이 필요할 때 이것들을 로드하세요:
references/systems.md— 팔레트를 처음부터 구축: 기본 색상 선택, 밝고 어두운 끝에서 채도를 유지, 색조 회전, 따뜻함/차가움 회색, 그리고 못생긴 색상 없이 대비 비율을 달성하기 위한 두 가지 탈출구.references/diagnose.md— 증상 → 수정 표. 새로 구축하는 것이 아니라 기존 UI를 개선하는 작업일 때 먼저 로드하세요.references/techniques.md— 깊이와 빛 시뮬레이션, 두 부분 그림자, 기준선 정렬, 자간, 기본 컴포넌트 모양에서 벗어나기, 사용자 업로드 이미지 처리.