박스 모델


CSS로 요소 간 간격을 조절하기 시작하면 누구나 한 번쯍 겪는 문제가 있습니다. 너비를 지정하고 패딩을 조금 넣었더니, 요소가 지정한 값보다 더 넓게 나오는 것입니다. 두 문단이 숫자로 계산한 것보다 더 가깝게 붙어 있기도 합니다. 이것은 버그가 아닙니다. 각 요소가 차지하는 공간을 결정하는 규칙인 박스 모델 때문이며, 이 그림을 한 번 머릿속에 넣어두면 간격에 관한 대부분의 의외의 상황이 더 이상 의외가 아니게 됩니다.
모든 요소는 박스입니다
CSS는 페이지 위의 모든 요소를, 단어 하나나 링크 하나까지도 사각형으로 취급합니다. 이 사각형은 안쪽에서 바깥쪽으로 쌓인 네 개의 층으로 이루어지는데, 이것이 바로 **박스 모델**입니다. 가운데에 콘텐츠가 있고, 그 주위에 패딩, 그다음 테두리, 가장 바깥에 마진이 있습니다.
벽에 걸린 액자 사진을 떠올려 보세요. 사진이 콘텐츠입니다. 사진 주위의 흰 매트는 패딩으로, 액자 안쪽의 여유 공간입니다. 나무 액자 틀 자체는 테두리입니다. 그리고 이 액자와 옆 액자 사이의 빈 벽면이 마진입니다. 스타일을 적용하는 모든 요소는 안쪽에서 바깥쪽으로 이렇게 똑같은 방식으로 구성됩니다.
.card {
padding: 16px; /* 콘텐츠 안쪽 여백 */
border: 2px solid #333; /* 액자 틀 */
margin: 24px; /* 바깥쪽 여백, 이웃 요소를 밀어냄 */
}padding, border, margin
세 가지 간격 층은 각각 하나의 역할을 합니다. **패딩**은 안쪽 공간으로, 콘텐츠와 테두리 사이에 있습니다. 마진은 바깥쪽 공간으로, 다른 요소를 밀어냅니다. 테두리는 그 사이에 그려진 선입니다.
네 면에 한 번에 하나의 값을 지정할 수도 있고, 특정 면만 지정할 수도 있습니다:
.card {
padding: 20px; /* 네 면 모두 20px */
margin-bottom: 32px; /* 아래쪽 면만 */
}padding: 20px 같은 축약형은 위, 오른쪽, 아래, 왼쪽을 한 번에 지정하는 빠른 방법입니다. 한 면만 다르게 지정해야 할 때는 margin-bottom 같은 구체적인 속성을 사용하세요.
padding을 쓰고, 두 박스가 너무 가까이 붙어 있으면 margin을 쓰세요. padding: 20px 같은 값 하나로 네 면 모두를 지정할 수 있고, 한 면만 바꿔야 할 때는 margin-bottom처럼 면을 지정하면 됩니다. box-sizing: content-box vs border-box
거의 모든 사람이 걸려드는 함정이 여기 있습니다. 카드에 width: 300px를 지정하고 패딩을 조금 넣었더니, 화면에 나온 카드가 300픽셀보다 더 넓어져 있습니다. 여러분이 뭔가를 잘못한 게 아닙니다. 기본적으로 width는 가운데의 콘텐츠만 측정하고, 패딩과 테두리는 그 위에 추가로 더해지기 때문입니다.
너비를 기대한 대로 동작하게 만드는 한 줄짜리 해결책이 있습니다. box-sizing: border-box를 지정하면, 이제 여러분이 입력한 너비는 패딩과 테두리를 포함한 박스 전체의 너비가 됩니다:
.card {
box-sizing: border-box; /* 이제 width에 패딩과 테두리가 포함됨 */
width: 300px;
padding: 20px; /* 카드는 340px가 아니라 300px 너비를 유지함 */
}width는 가운데의 콘텐츠만 측정하기 때문에, 패딩과 테두리가 더해지면 박스가 입력한 숫자보다 더 커집니다. box-sizing: border-box를 지정하면 이 문제가 해결됩니다. 이제 너비는 패딩과 테두리를 포함한 박스 전체를 의미합니다. 저도 이것 때문에 오랫동안 헷갈렸으니, 일찍 기억해두면 좋습니다. 마진 상쇄
한 가지 더 놀랄 만한 상황이 있는데, 이번엔 마진이 겹쳐 쌓이는 방식에 관한 것입니다. 문단 두 개를 위아래로 놓고 첫 번째에 아래쪽 마진 24px, 두 번째에 위쪽 마진 16px를 주면, 둘 사이에 40px의 간격이 생길 거라고 예상할 수 있습니다. 하지만 실제로는 24px가 나옵니다.
이것을 **마진 상쇄**라고 부릅니다. 두 세로 마진이 만나면, 브라우저는 이 둘을 더하지 않습니다. 둘 중 더 큰 값만 유지하고 작은 값은 버립니다. 그래서 더 큰 마진이 이기고, 간격은 40px가 아니라 24px가 됩니다. 이 현상은 위쪽과 아래쪽 마진에서만 일어나며, 패딩에서는 절대 일어나지 않습니다.
.intro {
margin-bottom: 24px;
}
.details {
margin-top: 16px;
/* 둘 사이의 간격은 더 큰 마진인 24px이며, 40px가 아님 */
}24px가 위쪽 16px를 만나면 40px가 아니라 24px 간격이 나옵니다. 이 현상은 위쪽과 아래쪽 마진에서만 일어나며, 처음 겪으면 누구나 놀랍니다. 
