01 — Box Model
모든 HTML 요소는 4겹의 동심 사각형이다 — content → padding → border → margin. 이 4겹의 합이 어디까지를 “요소의 크기”로 칠 것인지가 박스 모델이고, 2012년 이후
border-box가 사실상 표준이 되었다.
Why — 왜 박스 모델이 모든 것의 출발인가
CSS 렌더링 엔진은 트리의 모든 노드를 사각형으로 환원해서 레이아웃을 계산한다. text run 하나, 인라인 SVG 하나, <div> 하나 — 전부 박스다. 박스의 크기 계산이 어긋나면:
width: 100%인데 가로 스크롤이 생긴다.flex: 1인 자식들이 의도와 다른 비율로 늘어난다.- 그리드 셀이
gap을 무시하고 겹친다. position: absolute요소의inset이 어긋난다.
박스 모델은 CSS의 산수다. 모든 계산이 여기서 시작한다.
How — 박스는 어떻게 구성되나
브라우저는 모든 요소에 대해 4개의 사각형을 계산한다. 안쪽부터:
┌─────────────────────────────── margin box ──────┐
│ margin (배경 없음, 투명) │
│ ┌────────────────────────── border box ──┐ │
│ │ border (색·스타일 가짐) │ │
│ │ ┌─────────────────── padding box ──┐ │ │
│ │ │ padding (배경색이 칠해지는 영역) │ │ │
│ │ │ ┌─────────── content box ──┐ │ │ │
│ │ │ │ content │ │ │ │
│ │ │ └───────────────────────────┘ │ │ │
│ │ └────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘box-sizing 속성이 “width와 height는 이 중 어느 박스를 가리키는가” 를 결정한다.
box-sizing | width/height가 의미하는 것 | 비고 |
|---|---|---|
content-box (기본값) | content box만 | W3C CSS1 초안 모델 |
border-box | padding + border 포함 (margin 제외) | IE5가 먼저 채택, 2012년 이후 사실상 표준 |
계산 예시
.box {
width: 200px;
padding: 20px;
border: 5px solid;
margin: 10px;
}box-sizing | 실제 요소 너비 | margin 포함 | 비고 |
|---|---|---|---|
content-box | 200 + 20·2 + 5·2 = 250px | 270px | width에 padding/border가 더해진다 |
border-box | 200px | 220px | content는 200 - 50 = 150px로 줄어든다 |
What — 구체 사양과 패턴
1) 모든 리셋의 첫 줄
*, *::before, *::after {
box-sizing: border-box;
}이 한 줄은 normalize.css, modern CSS reset, Tailwind preflight, shadcn/ui, Bootstrap 5 — 모든 모던 리셋에 들어 있다.
2) margin collapsing (마진 상쇄)
블록 박스의 수직 인접 margin은 합쳐진다 (flex/grid 자식은 예외).
h2 { margin-bottom: 24px; }
p { margin-top: 16px; }
/* h2와 p 사이 간격은 40px이 아니라 max(24, 16) = 24px */상쇄 발생 조건:
- 인접한 형제 (sibling)
- 부모와 첫 자식 / 마지막 자식 (부모에
padding이나border없을 때) - 빈 블록의 위·아래 margin
상쇄를 막는 법:
- 부모를 BFC로 만든다 (
display: flow-root/flex/grid/overflow: hidden) padding이나border를 1px이라도 준다- flex/grid 컨테이너 안에서는 애초에 발생하지 않는다
3) min-content / max-content / fit-content
width/height에 키워드 값을 줄 수 있다 — intrinsic sizing.
.button { width: max-content; padding: 8px 16px; }
/* 텍스트가 줄바꿈 없이 가장 좁은 너비로 */| 키워드 | 의미 |
|---|---|
min-content | 줄바꿈 가능한 가장 작은 너비 (가장 긴 단어 폭) |
max-content | 줄바꿈 없는 가장 큰 너비 |
fit-content(N) | min과 max 사이에서 N으로 clamp |
auto | 부모와 흐름에 맡김 (기본값) |
4) aspect-ratio (2021년 이후 Baseline)
박스 모델 위에 종횡비를 강제하는 모던 속성.
.video-wrapper { aspect-ratio: 16 / 9; width: 100%; }
.avatar { aspect-ratio: 1; width: 48px; }width만 정하면 height가 자동 계산된다. 과거의 padding-bottom: 56.25% hack을 폐기시킨다.
What-if — 잘못 쓰면
1) box-sizing 없이 width: 100% + padding
.col { width: 100%; padding: 0 16px; }
/* content-box 기본값이면 → 실제 너비 = 100% + 32px → 가로 스크롤 발생 */이게 *“왜 가로 스크롤이 생기지”*의 90%다.
2) 마진 상쇄를 모르는 채로 레이아웃 짜기
.section { margin-top: 80px; }
.section:first-child { margin-top: 0; }
/* 부모의 padding-top이 0이면, 부모 위로 80px이 "삐져나간다" — margin이 부모를 뚫고 합쳐진다 */해결: 부모를 BFC로 (display: flow-root).
3) width: auto인 inline 요소에 width를 주려는 시도
<span>에 width: 200px을 줘도 무시된다. inline 박스는 content가 결정한다. display: inline-block 또는 block이 필요.
4) flex/grid 자식의 min-width: auto
flex/grid 자식의 기본 min-width는 auto이고, 이는 content의 min-content다. 긴 텍스트가 있으면 자식이 부모를 넘어선다.
.flex-child { min-width: 0; } /* 또는 overflow: hidden */이게 “flex 자식이 부모를 뚫고 나가는” 현상의 정답이다.
Insight — Paul Irish의 한 줄 트윗이 사실상 표준을 바꿨다
2012년 2월 1일 — Paul Irish는 자신의 블로그에 다음 한 줄을 올렸다:
*, *:before, *:after { box-sizing: border-box; }제목은 “box-sizing: border-box FTW”. 그는 이 한 줄이 “CSS 작업의 30%를 줄여준다” 고 썼다.
이전까지 웹 개발자들은 두 박스 모델 사이에서 끊임없이 계산기를 두드렸다. width: 100%에 padding: 20px을 주려면 calc(100% - 40px)을 쓰거나, padding을 내부 자식으로 옮기거나, width를 줄여서 보정해야 했다.
흥미로운 점은 IE5(1999)가 처음부터 border-box였다는 것. 당시 W3C는 IE5를 “버그”라 불렀고, IE6에서 quirks mode를 도입해 standards mode와 분리시켰다. 그러나 시간이 지나 보니, IE5의 디자이너가 옳았다 — 사람이 “박스의 크기”라고 부르는 것은 보통 border까지를 포함하는 시각적 경계다.
CSS3 명세에 box-sizing 속성이 들어간 것이 2003년, 모든 브라우저가 지원한 것이 2012년 즈음. 그리고 그 해 Paul Irish의 트윗이 “이걸 모든 프로젝트의 첫 줄로 쓰자” 는 합의를 만들어냈다. 표준이 늦게 따라오고, 사실상 표준이 먼저 자리잡는 — 이게 CSS의 진화 패턴이다.
오늘날 Bootstrap, Tailwind, shadcn/ui, Material UI는 모두 첫 줄에 *, *::before, *::after { box-sizing: border-box }를 둔다. 13년이 지난 한 줄 트윗의 유산이다.
요약 + Mermaid
- 모든 요소는 4겹의 박스 (content → padding → border → margin).
box-sizing: border-box가 사실상 표준 (Paul Irish 2012).- 마진 상쇄는 블록 흐름의 특수 규칙 — flex/grid·BFC에서는 무효.
min-content/max-content/fit-content로 intrinsic sizing.aspect-ratio로 종횡비를 선언적으로 잡는다.- flex 자식이 부모를 뚫으면
min-width: 0.