04 — Sizing (width · min/max · intrinsic · aspect-ratio)
한 줄 답:
width: 100%는 부모의 100%,width: max-content는 내용물의 줄바꿈 없는 너비,width: fit-content는 max-content와 부모 한계의 작은 쪽이다. 이 세 의미를 구분 못 하면 반응형은 영원히 깨지고,aspect-ratio의 등장으로 padding-bottom 해킹은 폐기됐다.
Why — 왜 sizing이 어려운가
CSS 박스 크기는 세 종류의 협상이다:
- Explicit —
width: 200px,width: 50% - Intrinsic — 내용물이 자연스럽게 차지하려는 크기 (
min-content,max-content,fit-content) - Implicit / Auto — 컨테이너와 내용물 사이의 알고리즘이 자동 결정
이 셋이 충돌할 때 min/max constraint가 중재한다. “width: 100%인데 부모를 삐져나간다” 같은 사고는 거의 모두 intrinsic min-content가 explicit보다 크기 때문이다.
.card { width: 100%; }
.card .url { /* 긴 영문 URL */ }
/* → URL이 줄바꿈 안 되면 .card의 min-content가 부모보다 큼
→ .card는 부모를 삐져나가거나 스크롤 발생 */How — 어떻게 동작하나
1) Box-sizing: 사이즈에 무엇이 포함되나
/* 기본 (W3C) */
.x { box-sizing: content-box; } /* width = content만 */
.x { width: 200px; padding: 20px; border: 1px; }
/* 실제 차지 = 200 + 40 + 2 = 242px */
/* 모던 BP */
.x { box-sizing: border-box; } /* width = content + padding + border */
.x { width: 200px; padding: 20px; border: 1px; }
/* 실제 차지 = 200px (content는 158px) */2026 BP: 글로벌 reset에
*, *::before, *::after { box-sizing: border-box }. 모든 디자인 시스템이 이 가정 위에 동작한다.
2) Intrinsic sizing — 내용물의 본성
| 키워드 | 의미 |
|---|---|
min-content | 모든 줄바꿈 후 가장 긴 분할 불가 단위의 너비 |
max-content | 줄바꿈 없이 한 줄로 펼친 너비 |
fit-content | min(max-content, max(min-content, stretch)) — 가능하면 max-content, 공간 부족하면 줄어듦 |
fit-content(20rem) | 위와 같되 상한이 20rem — 모달 등 적당히 크되 너무 크지 않게 |
auto | block은 stretch(부모 채움), inline은 max-content |
stretch | 부모 사용 가능 공간 채움 (구 -webkit-fill-available) |
3) Width의 결정 순서
1. width 또는 inline-size 명시되었나? → 그 값
2. 명시 없으면 → display에 따라 다름
- block: stretch (부모 너비)
- inline-block / flex / grid item: shrink-to-fit ≈ fit-content
3. min-width / max-width로 clamp
4. min-width의 기본값은 *auto*인데, 이게 *min-content와 비슷한* 행동을 한다 → 함정.card {
width: 100%; /* 부모를 채워라 */
min-width: 0; /* ★ flex/grid 안에서 흔히 필요: 기본 min-width(=auto)가
min-content이라서 부모를 삐져나갈 수 있음 */
}4) aspect-ratio — padding-bottom 해킹의 종말
/* 2020년 이전 (해킹) */
.thumbnail {
position: relative;
padding-bottom: 56.25%; /* 16:9 비율 */
height: 0;
}
.thumbnail img {
position: absolute;
inset: 0;
width: 100%; height: 100%;
}
/* 2021년+ */
.thumbnail {
aspect-ratio: 16 / 9;
width: 100%;
}
.thumbnail img { width: 100%; height: 100%; object-fit: cover; }aspect-ratio의 동작:
- width 또는 height 중 하나만 결정되면, 나머지를 비율로 계산.
- 둘 다 명시되면 무시.
- 콘텐츠가 박스보다 크면 비율을 깨고 콘텐츠 우선 (덮어쓰려면
min-height: 0등).
5) min/max 단축 — clamp()와의 관계
/* 옛날 */
.heading { font-size: 24px; min-font-size: 16px; max-font-size: 32px; }
/* → 위 문법 없음. media query로 분기 */
/* 모던 (CSS Values 4) */
.heading { font-size: clamp(1rem, 2.5vw, 2rem); }
/* clamp(min, preferred, max) */→ clamp()는 sizing 모든 곳에 적용 가능: width, padding, font-size, gap …
What — 구체 사양
Sizing 속성 전수
| 속성 | 의미 |
|---|---|
width / height | 박스 크기 (물리 축) |
inline-size / block-size | 박스 크기 (논리 축) ★ 모던 |
min-width / min-height | 하한 |
max-width / max-height | 상한 |
min-inline-size / min-block-size | 논리 하한 |
aspect-ratio | 종횡비 |
box-sizing | content-box / border-box |
Intrinsic 키워드
| 키워드 | width에 적용 시 | 호환성 (2026) |
|---|---|---|
auto | display 따름 | 모든 브라우저 |
min-content | 가장 좁게 가능한 너비 | 모든 브라우저 |
max-content | 줄바꿈 없는 너비 | 모든 브라우저 |
fit-content | min(max-content, available) | 모든 브라우저 |
fit-content(<length>) | 상한 지정 fit-content | 2022+ baseline |
stretch | 부모 채움 | 2024+ baseline (구: -webkit-fill-available) |
aspect-ratio 값
.x { aspect-ratio: 1 / 1; } /* 정사각 */
.x { aspect-ratio: 16 / 9; } /* 비디오 */
.x { aspect-ratio: 4 / 3; } /* 클래식 */
.x { aspect-ratio: 1.618; } /* 황금비 (단일 숫자 = w/h) */
.x { aspect-ratio: auto 16/9; } /* 자연 비율 우선, 없으면 16/9 */Sizing 결정 트리
display: block
├─ width 명시? → 그 값 (min/max clamp)
└─ 명시 없음? → stretch (부모 너비)
display: inline-block / flex-item / grid-item
├─ flex-basis 또는 grid 정의가 우선
├─ width 명시? → 그 값
└─ 명시 없음? → fit-content (max-content 캡)Flex/Grid에서의 min-width: 0 함정
.flex-container { display: flex; }
.flex-item { flex: 1; overflow: hidden; }
/* → 안에 긴 텍스트가 있으면 flex-item이 줄어들지 않음
원인: flex-item의 min-width 기본값이 auto = min-content */
.flex-item { min-width: 0; overflow: hidden; } /* ★ 해결 */
/* 또는 flex shorthand: */
.flex-item { flex: 1 1 0; min-width: 0; }What-if — 잘못 쓰면
1) width: 100%인데 부모를 삐져나감
.parent { width: 300px; }
.child { width: 100%; padding: 20px; box-sizing: content-box; }
/* → child = 300 + 40 = 340. 부모 삐져나감 */
/* 해결 1: */
.child { box-sizing: border-box; } /* 100%가 padding 포함 */
/* 해결 2 (이미 border-box인데 내용이 큰 경우) */
.child { width: 100%; min-width: 0; overflow-wrap: anywhere; }2) 긴 영문 URL이 카드를 부숨
<div class="card">
<p>https://verylongdomainwithoutanyspaces.example.com/path/to/something</p>
</div>/* URL의 min-content가 카드보다 큼 */
.card { width: 300px; } /* 부수어짐 */
/* 해결 */
.card p {
overflow-wrap: anywhere; /* 어느 글자든 줄바꿈 */
/* 또는 */
word-break: break-word; /* 레거시 */
}3) padding-bottom 해킹이 모던 코드에 남아 있음
/* 2026년에는 즉시 교체 */
.thumb { padding-bottom: 56.25%; height: 0; }
/* → */
.thumb { aspect-ratio: 16/9; }→ 모든 브라우저 baseline. 코드 리뷰에서 발견하면 바로 마이그레이션.
4) width: 100vw가 가로 스크롤을 만듬
.hero { width: 100vw; }
/* → 100vw는 스크롤바 너비를 포함한다 (브라우저별 다름)
→ 본문이 스크롤 있는 경우 100vw > body width
→ 가로 스크롤 발생 */
/* 해결 */
.hero { width: 100%; } /* 부모 너비 */
/* 또는 */
.hero { width: 100dvw; } /* 동적 viewport (모바일 주소창 고려) */→ vw/vh 대신 dvw/dvh/svw/svh/lvw/lvh (2024+ baseline, 07-responsive).
5) aspect-ratio가 무시됨
.x { width: 200px; height: 100px; aspect-ratio: 16/9; }
/* → width와 height가 모두 명시되어 aspect-ratio 무시 */
/* 해결 */
.x { width: 200px; aspect-ratio: 16/9; } /* height 자동 = 112.5px */6) Flex/Grid item이 안 줄어듦
min-width: 0 빠뜨림 → 항목 4번 참조. 모든 flex item에 min-width: 0을 기본으로 깔아두는 reset도 있다.
Insight — 흥미로운 이야기
box-sizing: border-box는 2006년 Paul Irish의 글에서 표준이 됐다
원래 CSS는 content-box가 기본이었다. 1996년 표준 작성 당시 “width는 콘텐츠 영역” 이 학술적으로 깔끔해 보였다. 하지만 실무에서는 항상 박스 전체 크기로 사고하기 때문에 잘못된 기본값이었다.
IE5(1999)는 quirks mode에서 border-box를 기본으로 했다 — 틀린 구현이라 욕먹었지만, 결국 그게 더 직관적이라는 게 증명됐다. 2011년 Paul Irish의 “box-sizing: border-box FTW” 글 이후 모든 CSS reset에 들어갔고, 2026년 디자인 시스템은 전체 border-box를 가정한다.
aspect-ratio는 5년의 논쟁 끝에 표준이 됐다
padding-bottom 해킹은 2010년대 후반에 너무 광범위해서 표준 위원회가 무시할 수 없었다. 하지만 어떻게 명세할 것인가가 어려웠다:
- 부모 너비가 안 정해진 상태에서 비율로 height를 결정 → 순환 참조
- 콘텐츠가 비율보다 크면 어떻게? → 덮어쓸 것인가, 자를 것인가
결국 “width 또는 height 하나가 결정되면 비율로 나머지” + “콘텐츠가 크면 비율을 깬다” 로 명세됐다. Chrome 88(2021), Safari 15(2021), Firefox 89(2021)에서 동시 출시 — 2021년이 CSS의 큰 분기점이었다.
min-content는 LaTeX에서 왔다
Donald Knuth의 TeX(1978)는 paragraph breaking에서 이미 minimum width와 maximum width 개념을 썼다. CSS WG는 조판 소프트웨어의 30년 노하우를 intrinsic sizing이라는 이름으로 가져왔다 (CSS Sizing 3, 2018 명세).
이는 CSS가 잡지·신문 조판의 디지털 후예라는 정체성을 다시 확인하는 대목이다.
stretch라는 키워드
2024년에야 width: stretch가 baseline에 들어왔다 (Chrome/Safari/Firefox). 그 전에는 -webkit-fill-available, -moz-available 같은 벤더 프리픽스로만 가능. 의미는 “부모의 가용 공간을 채워라” — width: 100%와 미묘하게 다르다 (마진을 포함한 가용 공간).
.x { width: 100%; margin: 1rem; } /* width=100%, 결국 부모 폭 + 2rem 차지 */
.x { width: stretch; margin: 1rem; } /* 부모 폭 - 2rem 사용 (적절히 들어맞음) */→ 모달이나 카드의 “부모에 1rem 여백 두고 채우기” 패턴이 한 줄로 가능해진다.
요약 + 다이어그램
Width는 explicit · intrinsic · constraint의 협상이다.
100%는 부모 기준,max-content는 내용물 기준,fit-content는 둘의 작은 쪽.min-width: 0은 flex/grid에서 기본 min-content auto를 끄는 모던 BP.aspect-ratio로 padding-bottom 해킹은 폐기.clamp()로 fluid sizing이 가능해졌다.
다음 문서:
05-logical-properties.md—width를 잊고inline-size로 옮기는 이유와 한·중·일·아랍어 대응.