한 줄 요약 — CSS에서 모든 요소는 네 겹의 상자입니다. 안쪽부터 내용(content) → 완충재(padding) → 포장지(border) → 바깥 간격(margin) 순서로 감싸고, 이 네 겹을 합한 크기가 화면에서 실제로 차지하는 자리가 됩니다. 그런데 기본값인 box-sizing: content-box에서는 width가 "내용물만의 너비"라서 padding·border를 더할수록 박스가 자꾸 커집니다. box-sizing: border-box로 바꾸면 width가 "포장지까지 포함한 너비"가 되어, 우리가 머릿속으로 그리는 크기와 화면이 비로소 맞아떨어집니다.

학습 목표

  • 박스 모델의 네 겹(content·padding·border·margin)이 각각 무엇을 의미하는지 설명할 수 있다.
  • paddingmargin의 차이를 한 문장으로 말할 수 있다.
  • content-boxborder-box에서 같은 width: 200px이 왜 다른 결과를 내는지 안다.
  • 인접한 두 박스의 세로 margin이 합쳐지는 현상(margin collapsing)을 알아채고 우회할 수 있다.

오늘의 비유 — 선물 상자의 내용물·완충재·포장지·간격

택배로 받은 선물 상자 하나를 떠올려 봅니다. 가장 안쪽에는 진짜 선물, 즉 내용물이 있습니다. 내용물이 흔들리지 않도록 상자 안쪽 벽과 선물 사이에 채워 둔 뽁뽁이·종이 충전재가 완충재입니다. 그 바깥을 단단히 감싸는 포장지가 있고, 마지막으로 다른 택배 박스와 겹치지 않도록 보관함에서 떨어뜨려 놓는 바깥 간격이 있습니다. CSS의 박스 모델은 정확히 이 네 겹입니다 — 안에서부터 content, padding, border, margin.

여기서 두 단어가 자주 헷갈립니다. 완충재(padding)는 포장지 안쪽, 즉 내용물과 포장지 사이의 공간입니다. 박스 자체의 일부예요. 바깥 간격(margin)은 포장지 바깥, 즉 내 상자와 옆 상자 사이의 빈 자리입니다. 박스의 일부가 아니라 박스끼리의 거리입니다. 같은 5cm라도, 5cm를 상자 안쪽에 채우면 손에 들리는 상자 자체가 커지고, 상자 바깥에 두면 상자 크기는 그대로지만 옆 상자와의 거리가 멀어집니다. 이 한 끗 차이가 박스 모델의 거의 전부입니다.

핵심 개념

네 겹을 그림으로 그리면

박스 모델을 안쪽부터 바깥으로 펼치면 이렇습니다.

┌──────────────────────────── margin (바깥 간격) ────────────────────────────┐
│  ┌──────────────────────── border (포장지) ────────────────────────┐       │
│  │  ┌──────────────────── padding (완충재) ────────────────────┐  │       │
│  │  │                                                            │  │       │
│  │  │                  content (내용물)                          │  │       │
│  │  │                                                            │  │       │
│  │  └────────────────────────────────────────────────────────────┘  │       │
│  └────────────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────────────┘

화면에서 실제로 차지하는 자리는 border 바깥까지입니다. margin은 자기 박스와 이웃 박스 사이의 빈 자리라서, 박스 자체의 크기에는 포함되지 않습니다 — 다만 다른 박스가 그 자리만큼 가까이 오지 못합니다.

padding과 margin은 무엇이 다른가

padding은 박스 안쪽의 여백입니다. 늘릴수록 박스 자체가 커집니다. 배경색이나 포장지(border)가 적용되는 범위 안에 들어갑니다.

.gift {
  background: bisque;
  padding: 24px;
  border: 2px solid sienna;
}
<div class="gift">생일 선물</div>

위 박스는 글자 주위에 24px씩 옅은 베이지색 배경이 함께 늘어납니다. 배경이 padding 자리까지 같이 채워지기 때문입니다.

margin은 박스 바깥의 간격입니다. 박스 자체의 크기는 그대로지만, 옆 박스와의 거리가 벌어집니다. margin 자리에는 배경색도 칠해지지 않습니다 — 정말로 "비어 있는 자리"입니다.

.gift + .gift {
  margin-top: 24px;
}

선물 상자 두 개를 위아래로 쌓아 두는데, 두 번째 박스 위에 24px의 빈 자리를 만들어 첫 번째 박스와 닿지 않게 한 셈입니다. 박스 자체가 커진 게 아니라, 박스끼리의 사이가 벌어진 것입니다.

한 문장으로: padding은 상자 안에 채우는 완충재, margin은 상자 바깥에 두는 간격.

box-sizingwidth가 어디까지를 가리키는가

여기서 가장 자주 사람을 당황시키는 부분으로 들어갑니다. width: 200px이라고 적었을 때, 200px이 가리키는 자리가 어디까지인지가 box-sizing 값에 따라 달라집니다.

기본값인 content-box에서 width내용물(content)만의 너비입니다. padding과 border는 그 위에 추가로 더해집니다.

.gift {
  box-sizing: content-box; /* 브라우저 기본값 */
  width: 200px;
  padding: 20px;
  border: 4px solid sienna;
}

이 박스가 실제로 화면에서 차지하는 가로 자리는 200 + 20*2 + 4*2 = 248px입니다. "200px 박스를 하나 만들었는데 왜 자꾸 한 줄이 안 맞지?" 하는 상황의 거의 전부가 여기서 생깁니다.

box-sizing: border-box로 바꾸면, width포장지(border) 바깥까지 합친 너비가 됩니다. padding과 border는 그 200px 안에서 자기 자리를 가져갑니다.

.gift {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 4px solid sienna;
}

이 박스가 차지하는 가로 자리는 그냥 200px입니다. padding을 키우면 안쪽 내용물 공간이 줄어들 뿐, 박스 전체 크기는 그대로입니다. 머릿속으로 "이 카드는 200px짜리"라고 그렸을 때 화면도 정확히 그렇게 그려지는 모드입니다.

요즘 거의 모든 프로젝트는 첫 줄에 이걸 깔고 시작합니다.

*,
*::before,
*::after {
  box-sizing: border-box;
}

별표(*)는 모든 요소를 가리키는 선택자입니다. "모든 요소와 그 의사 요소를 border-box로 둔다"는 한 줄짜리 약속이에요. 이 한 줄이 들어가면 width·height가 직관과 어긋나는 일이 거의 사라집니다.

margin collapsing — 위아래로 인접한 margin은 더해지지 않는다

박스 두 개를 위아래로 쌓고, 위 박스에 margin-bottom: 30px, 아래 박스에 margin-top: 20px을 줬다고 합시다. 직관으로는 둘 사이의 빈 자리가 50px이 되어야 할 것 같지만, 실제로는 둘 중 큰 쪽만 적용되어 30px이 됩니다. 두 margin이 같은 자리를 공유하면서 더해지지 않고 흡수된 것입니다. 이 현상을 margin collapsing(마진 상쇄·마진 병합)이라고 부릅니다.

세로 방향에서만 일어나고, 좌우 방향에서는 일어나지 않습니다. 그리고 padding, border, 인라인 콘텐츠 같은 무언가가 두 margin 사이에 끼어 있으면 상쇄가 풀립니다. 부모-자식 사이에서도 비슷한 일이 생기는데, 부모에 padding이나 border가 한 줄이라도 있으면 그 둘이 더 이상 맞붙어 있지 않게 되어 상쇄가 끊어집니다.

당장은 "세로 margin은 서로를 흡수한다, 좌우는 아니다" 한 줄만 기억하면 충분합니다. 정확한 규칙은 의외로 까다로워서 MDN의 margin collapsing 페이지를 그때그때 참고하는 쪽이 빠릅니다.

함께 따라하기 — box-sizing을 토글해 너비 변화를 눈으로 보기

day-16 폴더에 index.htmlstyle.css를 만들고, 같은 선물 상자 두 개를 다른 box-sizing으로 그려 봅니다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8">
    <title>박스 모델</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div class="gift content">content-box (기본값)</div>
    <div class="gift border">border-box</div>
  </body>
</html>
body {
  font-family: sans-serif;
  padding: 24px;
  background: #f6f3ee;
}

.gift {
  width: 200px;
  padding: 20px;
  border: 4px solid sienna;
  margin-bottom: 16px;
  background: bisque;
}

.gift.content {
  box-sizing: content-box;
}

.gift.border {
  box-sizing: border-box;
}

저장하고 브라우저로 열어 보면, 위 박스는 아래 박스보다 눈에 띄게 가로로 더 깁니다. 둘 다 width: 200px인데도요. 위 박스는 200px에 padding 40px과 border 8px이 더해져 실제로 248px을 차지하고, 아래 박스는 200px 안에서 padding과 border가 자기 자리를 가져갔기 때문에 딱 200px만 차지합니다.

크롬·사파리·파이어폭스 모두 개발자 도구 → Elements → 박스를 클릭하면 우측 패널 아래에 박스 모델 다이어그램이 뜹니다. 가운데부터 content(파랑) → padding(초록) → border(노랑) → margin(주황)이 색으로 구분되어 보이니, 두 박스를 번갈아 클릭해 각 자리에 적힌 숫자가 어떻게 다른지 직접 확인해 보세요.

마지막으로 두 박스 사이의 빈 자리도 살펴봅니다. .giftmargin-bottom: 16px만 적었는데, 두 박스 사이의 거리는 정확히 16px입니다 — 아래 박스에는 margin-top이 없어 상쇄될 짝이 없으니 그대로 16px이 그려진 것입니다. 만약 아래 박스에 margin-top: 12px을 따로 줘 본다면 둘 사이의 자리가 28px이 아니라 16px 그대로임을 확인할 수 있습니다. 둘 중 큰 쪽이 이긴 결과입니다.

흔한 실수 3가지

1. content-box인 줄 모르고 width를 계산해 레이아웃이 어긋난다

가장 자주 나오는 사고입니다. 카드 4장을 한 줄에 25%씩 배치하려고 다음처럼 적습니다.

.card {
  width: 25%;
  padding: 16px;
  border: 1px solid #ddd;
}

(이 코드는 의도와 다르게 동작합니다.) 기본값인 content-box에서 width: 25%는 내용물만 25%라는 뜻이라서, padding 32px과 border 2px이 추가로 붙습니다. 네 카드가 한 줄에 들어가야 하는데 합이 100%를 넘어버려, 마지막 카드가 다음 줄로 떨어집니다. "분명 25% 네 개인데 왜 한 줄에 안 들어가지?"의 정답이 거의 항상 이 자리입니다.

*,
*::before,
*::after {
  box-sizing: border-box;
}

.card {
  width: 25%;
  padding: 16px;
  border: 1px solid #ddd;
}

전역으로 border-box를 깔아 두면 width: 25% 안에 padding·border가 함께 들어가 네 카드가 정확히 한 줄에 떨어집니다. 처음 만드는 프로젝트라면 이 4줄을 가장 윗자리에 둬도 좋습니다.

2. paddingmargin을 같은 의미로 쓴다

"안쪽 여백"과 "바깥 간격"을 같이 보면, 두 박스 사이를 띄우려고 padding을 키우는 실수가 나옵니다.

.gift {
  padding: 40px;
  background: bisque;
  border: 2px solid sienna;
}

(박스 자체가 커집니다.) padding을 키우면 박스 안쪽이 늘어나서 박스 전체가 같이 커지고, 옆 박스와의 거리가 벌어지긴 하지만 그 거리에도 배경색이 같이 칠해진다는 차이가 있습니다. 글자 둘레의 공간이 갑자기 잔뜩 비어 보이는 디자인이 됩니다.

.gift {
  padding: 16px;
  background: bisque;
  border: 2px solid sienna;
  margin-bottom: 24px;
}

박스 안쪽 여유는 padding으로, 박스끼리의 거리는 margin으로 분리해 두면 두 속성을 따로따로 조정할 수 있습니다. 선물의 완충재와 보관함의 간격은 다른 일이라는 비유가 그대로 들어맞습니다.

3. 인접한 세로 margin이 합쳐지는 현상(margin collapsing)을 모른다

<section class="block">위쪽 카드</section>
<section class="block">아래쪽 카드</section>
.block {
  margin-top: 40px;
  margin-bottom: 40px;
}

(두 카드 사이는 80px이 아니라 40px입니다.) 위 카드의 margin-bottom: 40px과 아래 카드의 margin-top: 40px이 같은 자리를 공유하면서 더해지지 않고 흡수된 결과입니다. "분명 위아래 40px씩 줬는데 왜 사이가 좁아 보이지?"의 정답이 여기에 있습니다.

상쇄를 피하고 싶다면 두 margin 사이에 무언가가 끼어 있게 만들면 됩니다. 부모 컨테이너에 padding: 1px만 줘도 끊기고, 보통은 부모에 display: flex를 주거나 자식에 border·padding이 들어가는 자연스러운 흐름에서 알아서 풀립니다. 진짜 정확히 두 칸을 띄우고 싶다면 한쪽만 줘서 의도를 분명히 하는 것도 자주 쓰는 방법입니다.

.block + .block {
  margin-top: 40px;
}

위·아래 양쪽에 막연히 40px씩 적는 대신, 인접 형제(+)에만 margin-top을 주는 패턴은 상쇄 걱정이 아예 없고 코드 의도도 더 분명해집니다.

오늘 배운 것 체크리스트

  • 박스 모델의 네 겹(content·padding·border·margin)을 안쪽부터 바깥 순서로 말할 수 있다.
  • padding은 박스 안쪽 여백, margin은 박스 바깥 간격이라는 차이를 안다.
  • content-box에서 width는 내용물만의 너비이고, border-box에서는 border까지 포함한 너비라는 사실을 안다.
  • * { box-sizing: border-box; }를 전역으로 까는 이유를 설명할 수 있다.
  • 위아래로 인접한 두 박스의 세로 margin이 더해지지 않고 큰 쪽만 살아남는다는 것을 안다.

자주 묻는 질문

Q. paddingmargin은 결국 같은 거 아닌가요?

A. 보기엔 둘 다 "여백"이지만, 자리부터 다릅니다. padding은 박스 안쪽의 빈 자리라 박스 자체가 그만큼 커지고 배경색도 같이 칠해집니다. margin은 박스 바깥의 빈 자리라 박스 자체의 크기는 그대로지만 옆 박스와의 거리가 벌어지고, 그 자리엔 배경색이 들어가지 않습니다. "선물 안의 완충재 vs 선물 사이의 간격"이라고 외워 두면 거의 헷갈리지 않습니다.

Q. box-sizing: border-box는 왜 기본값이 아닌가요?

A. CSS가 처음 만들어질 때 content-box로 정해진 것이 그대로 표준이 되었기 때문입니다. 다만 거의 모든 실무 프로젝트가 첫 줄에 * { box-sizing: border-box; }를 깔고 시작합니다. width가 직관과 어긋나지 않게 되어 레이아웃 계산이 훨씬 단순해지기 때문입니다. 이 한 줄이 없는 프로젝트는 거의 못 본다고 봐도 됩니다.

Q. width: 100%로 줬는데 박스가 부모를 넘어가요. 왜 그런가요?

A. 100%는 부모의 내용 영역(content) 너비를 가리킵니다. 여기에 padding이나 border가 더해지면, content-box에서는 박스가 부모보다 더 길어집니다. 해결은 똑같습니다 — box-sizing: border-box로 바꾸면 padding·border가 그 100% 안에서 자기 자리를 가져가서 부모 너비에 딱 맞게 들어갑니다.

다음 시간 예고

내일은 색상과 단위 — hex/rgb/hsl과 px/rem/em/% 어느 걸 언제를 다룹니다. 색을 표현하는 세 가지 방법과 길이를 재는 단위들을 정리하고, 같은 카드를 px·rem·em으로 만들어 브라우저 글자 크기를 바꿔도 안 깨지는 디자인이 무엇인지 직접 비교해 봅니다.

더 알아보기