CSS clamp() 정리 — 계산 원리부터 실전 패턴, 흔한 실수까지
반응형 크기, 왜 값을 여러 개 관리하게 되나
제목을 데스크톱에서는 40px, 모바일에서는 24px로 보이게 하고 싶다고 해봅시다. 미디어쿼리로 하면 중단점마다 font-size를 다시 선언해야 합니다. 게다가 중단점과 중단점 사이에서는 크기가 고정이라, 화면이 아무리 넓어져도 글자는 그대로 있다가 특정 지점에서만 갑자기 점프합니다. 요소가 늘어날수록 관리할 값도 같이 늘어나죠.
clamp()은 “이 값은 최소 이만큼, 최대 이만큼, 그 사이는 화면에 따라”를 한 줄로 표현하는 CSS 함수입니다. 앞부분은 아래 한 줄을 끝까지 예제로 씁니다.
font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem);
저도 처음에는 중단점마다 글자 크기를 전부 새로 적었습니다. 그러다 어느 순간 적는 숫자가 매번 비슷하다는 걸 알게 됐습니다. 모바일에서 쓰는 크기와 PC에서 쓰는 크기가 대강 정해져 있었던 거죠. 양 끝 값이 정해져 있다면 그 사이는 브라우저에 맡겨도 됩니다. 그때부터 글자 크기에 clamp()을 쓰기 시작했습니다.
clamp()가 받는 세 값
clamp()에는 항상 clamp(최소, 선호, 최대) 순서로 세 값을 넣습니다.
- 최소값
1.5rem(= 24px) — 결과가 이보다 작아지지 않음 - 선호값
1rem + 2vw— 화면에 따라 실제로 계산되는 값 - 최대값
2.5rem(= 40px) — 결과가 이보다 커지지 않음
최소·최대는 내가 원하는 하한·상한이라 어려울 게 없습니다. 걸리는 건 가운데 선호값이죠. 브라우저가 이 값을 어떻게 쓰는지부터 보고, 그다음에 이 숫자가 어디서 나온 건지 봅니다.
브라우저는 clamp()를 어떻게 계산하나
동작은 이 한 줄이 전부입니다.
선호값을 지금 화면 기준으로 계산한다 → 그게 최소보다 작으면 최소값을, 최대보다 크면 최대값을, 그 사이면 선호값을 그대로 쓴다.
선호값 1rem + 2vw를 풀어 쓰면 16px + (화면 너비 × 0.02)입니다. 1rem은 16px 고정, 2vw는 화면 너비의 2%니까요. 화면 너비별로 따라가 봅시다.
| 화면 너비 | 선호값 = 16 + 너비×0.02 | 실제 적용 |
|---|---|---|
| 320px | 16 + 6.4 = 22.4px | 24px — 최소값이 받침 |
| 400px | 16 + 8 = 24px | 24px |
| 800px | 16 + 16 = 32px | 32px — 선호값 그대로 |
| 1200px | 16 + 24 = 40px | 40px |
| 1600px | 16 + 32 = 48px | 40px — 최대값이 막음 |
좁은 화면에서는 최소값(24px)이 바닥을 받치고, 넓은 화면에서는 최대값(40px)이 천장을 막습니다. 그 사이 구간에서만 선호값이 살아서 부드럽게 커지죠. 미디어쿼리 없이 이 세 구간이 저절로 나뉩니다.
참고로 clamp(A, B, C)는 max(A, min(B, C))와 똑같습니다. 선호값 B를 최대값 C로 한 번 자르고, 그 결과를 최소값 A로 다시 받치는 것뿐입니다.
선호값은 왜 rem + vw 꼴인가
선호값의 역할은 “화면에 따라 변하는 중간 구간”을 그리는 겁니다. 그러려면 변하는 부분과 안 변하는 부분이 둘 다 필요합니다.
2vw— 화면 너비의 2%. 화면이 넓어지면 커집니다. 화면에 비례하는 부분.1rem— 언제나 16px. 화면과 무관합니다. 바닥을 잡아 주는 고정 부분.
만약 고정 부분 없이 vw만 쓰면(font-size: 4vw) 어떻게 될까요?
| 화면 너비 | 4vw |
|---|---|
| 320px | 12.8px — 너무 작음 |
| 768px | 30.7px |
| 1440px | 57.6px — 너무 큼 |
비율은 변하지만 문제가 둘 있습니다. 좁은 화면에서 글자가 걷잡을 수 없이 작아지고, 무엇보다 사용자가 브라우저를 확대(Ctrl + +)해도 글자가 안 커집니다. vw는 화면 픽셀만 보고 사용자의 확대·기본 글꼴 설정은 무시하거든요. 이건 웹 접근성 기준(WCAG 1.4.4 텍스트 크기 조정)에 걸립니다.
1rem을 더하면 이 고정 부분이 사용자의 글꼴 설정과 확대에 반응하므로, 확대하면 글자도 같이 커집니다. 그래서 선호값은 항상 rem(고정) + vw(가변) 꼴로 씁니다.
그 1rem과 2vw 숫자는 어떻게 나오나
내가 실제로 정하는 건 두 개의 목표점뿐입니다.
“화면 400px에서 글자 24px, 화면 1200px에서 글자 40px로 보이면 좋겠다.”
이 두 점을 잇는 직선은 세상에 딱 하나뿐이고, 선호값 1rem + 2vw는 그 직선을 CSS로 적은 것입니다. 두 조각의 역할은 이렇습니다.
2vw= 그 직선이 얼마나 가파른가 — 화면이 커질 때 글자가 커지는 속도1rem= 그 직선의 출발 높이 — 속도만으로는 안 맞는 나머지를 채우는 값
목표점 두 개만 정하면 이 두 숫자는 저절로 결정됩니다.
계산이 싫으면 여기서 넘어가세요. CSS clamp() 생성기에 “최소 24px, 최대 40px, 화면 400~1200px”만 넣으면
clamp(1.5rem, 1rem + 2vw, 2.5rem)이 바로 나옵니다. 아래는 그 숫자가 어떻게 나오는지 궁금한 사람을 위한 내용입니다.
가파른 정도 → 2vw
화면이 400px에서 1200px로, 즉 800px 넓어지는 동안 글자는 16px 커집니다(24 → 40). 비율로 보면 글자 증가폭이 화면 증가폭의 16 / 800 = 0.02, 곧 **화면 너비의 2%**입니다. vw가 바로 “화면 너비의 몇 %“라는 뜻이므로 그대로 2vw.
출발 높이 → 1rem
화면이 400px일 때 2vw는 400의 2% = 8px입니다. 그런데 이 지점의 목표는 24px이죠. 모자란 24 − 8 = 16px을 고정값으로 더하면 됩니다. 16px은 1rem.
검산
- 화면 400px →
1rem(16px) + 2vw(8px)= 24px ✓ - 화면 1200px →
16px + 2vw(24px)= 40px ✓
내가 정한 두 목표점을 정확히 지나갑니다.
어디에 쓰고, 어디에는 안 쓰나
clamp()이 잘 맞는 곳은 화면 크기에 따라 눈에 띄게 달라져야 하는 값입니다.
- 제목(
h1~h3)처럼 데스크톱과 모바일에서 크기 차이가 큰 요소 - 섹션 사이 세로 여백, 컨테이너 좌우 패딩
- 히어로 영역 높이, 큰 이미지의 최대 너비
반대로 안 쓰는 게 나은 곳도 있습니다.
- 본문 문단(
p) — 15~18px 고정이 대체로 더 편합니다. 읽는 크기는 화면 폭보다 사용자 설정을 따르는 게 낫습니다. - 테두리 두께, 아이콘 크기 같은 작은 고정 요소 — 유동적으로 만들 이득이 없습니다.
저도 처음에는 clamp()을 최대한 많은 곳에 쓰면 반응형이 저절로 해결돼서 일이 줄어들 거라고 생각했습니다. 실제로는 그렇지 않았습니다. 자잘한 여백, 이미지 크기, 아이콘 크기처럼 걸어 봐도 나아지는 게 없는 곳이 많았고, 오히려 고정값이 나은 곳도 있었습니다. 어디에 써야 하는지는 직접 걸어 보고, 화면에서 확인하고, 다시 지우기를 몇 번 반복하면서 알게 됐습니다.
실전 패턴
타이포 스케일 한 번에 잡기
제목 단계마다 clamp()을 쓰면 화면 크기와 무관하게 위계가 유지됩니다. 각 단계의 최소·최대만 서로 겹치지 않게 벌려 두면 됩니다.
h1 { font-size: clamp(1.75rem, 1.3rem + 2vw, 2.5rem); }
h2 { font-size: clamp(1.4rem, 1.15rem + 1.1vw, 1.875rem); }
h3 { font-size: clamp(1.15rem, 1.05rem + 0.5vw, 1.375rem); }
vw 값을 제목이 클수록 크게 두면, 화면이 넓어질 때 큰 제목이 더 많이 자라 위계 대비가 살아납니다.
섹션 여백과 컨테이너 패딩
여백을 고정값으로 두면 모바일에서 너무 벌어지거나 데스크톱에서 답답해집니다. clamp()으로 한 번에 조절합니다.
.section { padding-block: clamp(2rem, 1rem + 5vw, 5rem); }
.container { padding-inline: clamp(1rem, 0.5rem + 2vw, 2rem); }
.stack > * + * { margin-top: clamp(0.75rem, 0.5rem + 1vw, 1.5rem); }
여백에 쓸 때는 최소값을 충분히 확보하는 게 중요합니다. 좁은 화면에서는 vw 성분이 작아서 결과가 최소값에 붙기 쉽고, 그러면 최소값이 곧 모바일에서의 실제 여백이 됩니다.
유동 레이아웃
gap이나 width에도 그대로 쓸 수 있어서, 미디어쿼리 없이 카드 간격이나 사이드 여백을 조절할 수 있습니다.
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: clamp(0.75rem, 0.4rem + 1.5vw, 1.5rem);
}
minmax()가 열 개수를, clamp()이 간격을 맡아 레이아웃 전체가 중단점 없이 흐릅니다.
흔한 실수
- 최소·최대값 역전 —
clamp(2rem, …, 1rem)처럼 최소가 최대보다 크면 브라우저는 최대값을 무시하고 항상 최소값을 씁니다. 화면을 늘려도 값이 안 변하면 먼저 이걸 의심하세요. - 선호값을 순수
vw로만 — 위에서 본 대로 확대에 반응하지 않아 접근성 기준에 걸립니다. 선호값에rem을 반드시 섞으세요. - 변화가 너무 급함 — 좁은 화면 구간(예: 320→600)에 큰 변화를 몰면, 창을 조금만 줄여도 글자가 확 작아집니다. 두 목표점의 화면 너비 간격(예: 400→1200)을 넉넉히 잡으세요.
- 모든 곳에 적용 — 본문·버튼·라벨까지 전부
clamp()으로 만들면 유지보수만 어려워집니다. 크기 차이가 큰 곳에만 씁니다. - 최소값·고정값을 px로 —
px로 두면 사용자가 브라우저 기본 글꼴 크기를 키워도 따라오지 않습니다. 최소값과 선호값의 고정 부분 모두rem을 권합니다.
브라우저 지원
clamp()은 2020년 4월 이후 Chrome, Safari, Firefox, Edge 모든 최신 버전에서 동작합니다. 지금은 별도 폴백 없이 그냥 써도 됩니다.
요약
clamp(최소, 선호, 최대)는 선호값을 계산한 뒤 최소~최대 범위로 가두는 함수 (max(최소, min(선호, 최대))와 같음)- 선호값은
rem(고정) +vw(가변) 꼴 —vw만 쓰면 확대에 반응하지 않아 접근성 위반 vw값 = 화면이 넓어질 때 글자가 커지는 속도,rem값 = 그 속도로 못 채우는 나머지- 제목·여백·레이아웃 간격처럼 크게 달라져야 하는 값에 쓰고, 본문 글자 크기는 고정이 대체로 낫다
- 여백은 최소값이 곧 모바일 값이니 넉넉히, 두 목표점의 화면 너비 간격도 넉넉히
- 계산이 번거로우면 생성기에 목표 크기·화면 너비만 넣으면 됨