Logo

CSS 박스 모델과 box-sizing 속성

웹페이지 상의 모든 엘리먼트는 하나의 박스의 개념으로 모델링 할 수 있습니다. 이 박스 모델이라고 불리는 컨셉은 CSS의 근간이 되기 때문에 반드시 이해하고 있어야 합니다.

Box Model 이란?

우리가 웹페이지에 배치하는 모든 HTML 엘리먼트는 3개의 층을 가진 사각형 구조의 형태를 띠고 있습니다.

box-model

가장 외곽의 층을 margin 영역이라고 부르는데, 보통 주변에 위치한 다른 엘리먼트와의 상하좌우 간격을 두기 위해서 쓰입니다. 그 바로 아래 층을 border 영역이라고 부르는데, 경계선을 그리기 위해서 쓰이며, marginpadding과 달리 두께 뿐만 아니라 색상과 모양까지 지정할 수 있습니다. 그 바로 아래 층은 padding 영역이라고 불리는데, 컨텐츠와 경계선 사이의 간격을 지정하기 위해서 쓰입니다. 마지막으로 가장 중간에 있는 영역은 content 영역이라고 하며, 컨텐트의 width(너비)와 height(높이)를 지정해줄 수 있습니다.

예를 들어, 15px 두께의 margin5px 두께의 bordr 그리고 20px 두께의 padding을 가진 엘리먼트는 다음과 같이 만들 수 있습니다.

<div class="container">
  MARGIN
  <div class="box">CONTENT</div>
</div>
.container {
  background-color: orange;
  width: 400px;
  border: 1px solid red;
}

.box {
  color: white;
  background-color: green;
  width: 200px;
  height: 30px;
  padding: 20px;
  border: 5px dashed black;
  margin: 15px;
}

실제 너비감 결정

많은 분들이 박스 모델에서 가장 혼선을 겪는 부분이 바로 엘리먼트의 너비가 어떻게 결정이 되느냐 입니다. 예를 들어, 위 예제에서 .container 엘리먼트의 width400px이고 .box 엘리먼트의 width200px입니다. 그런데 얼핏봐도 초록색 영역이 오렌지색 영역의 절반 이상을 차지하고 있다는 것을 알 수 있습니다.

이는 박스 모델에서 width 속성은 순수하게 content 영역의 너비만을 포함하기 때문입니다. 따라서 실제 엘리먼트가 화면에서 차지하는 너비를 생각할 때는 paddingborder의 두께까지 고려해야합니다. 위 예제의 경우, 초록색 영역의 너비는 실제 content 영역의 너비에 좌우 padding 값과 좌우 border 값을 더한 250px이 됩니다.

200px + (20px * 2) + (5px * 2) = 250px

동일한 방식으로, .container 엘리먼트가 화면에서 자치하는 너비는 402px이 됩니다.

400px + (0px * 2) + (1px * 2) = 402px

이러한 CSS의 박스 모델의 디폴트 동작 방식이 웹페이지의 레이아웃을 잡을 때는 매우 불편하게 느껴질 수 있습니다. 왜냐하면, 부모 엘리멘트 안에 자식 엘리먼트를 빈틈없이 배치하려면 위와 같은 계산을 직접해줘야 하기 때문입니다.

예를 들어, .box 엘리먼트를 .container 엘리먼트 속에 딱 맞게 배치하려면 width 값을 몇으로 해줘야할까요? 우선, .box 엘리먼트의 margin 속성값을 0으로 설정하여, .container 엘리먼트와의 간격을 제거해야줘야 합니다. 그 다음, .container 엘리먼트의 가용 너비에서 좌우 padding 값과 좌우 border 값을 빼줘야 합니다.

400px - (20px * 2) - (5px * 2) = 350px

자, 이제 .box 엘리먼트의 width 속성값을 350px로 수정해주면 다음과 같이 두 엘리먼트가 빈틈없이 배치됩니다.

.box {
  margin: 0;
  width: 350px;
  /* 나머지 동일 */
}

반응형 레이아웃에서는 px과 같은 절대 단위 대신에 %와 같은 상대 단위를 사용하기 때문에 이 문제가 더욱 심각해질 수 있습니다. 지금까지 계산한 width 속상값을 다시 %로 환산해야된다고 생각해보세요… 그리고 상위 컨테이너의 width 속성값 마저도 px이 아닌 %로 정의되어 있다고 상상해보세요…

box-sizing

CSS 박스 모델의 이러한 불편한 부분은 box-sizing 속성을 이용하면 해결을 할 수 있습니다. box-sizing 속성의 기본값은 content-box 인데, 위에서 설명드린 것 처럼 width 속성값은 순수하게 content 영역의 너비만을 포함합니다. 하지만 box-sizing 속성값을 border-box로 변경해주면, width 속성값은 content 영역뿐만 아니라 paddingborder까지 포함시키게 됩니다.

따라서 .box 컨테이너의 width 속성을 .container 컨테이너의 width 속성값과 동일한 400px로 설정하면, .box 컨테이너가 .container 컨테이너 안으로 딱 맞게 들어가게 됩니다. 그리고 실제 content 영역의 너비는 400px에서 좌우 padding과 좌우 border 두께를 뺀 350px로 자동 계산됩니다.

400px - (20px * 2) - (5px * 2) = 350px

반응형 레이아웃에서 적합하도록 절대 길이인 400px 대신에 상대 길이인 100%로 바꿔줄 수도 있습니다. 만약에, box-sizing 속성이 content-box로 설정된 상황에서 100%로 설정해줬다면 .box 컨테이너의 너비가 .container 컨테이너를 초과하여 밖으로 삐져나왔을 것입니다. 왜냐하면 % 단위는 부모 엘리먼트의 너비를 기준으로 하는데, 그럼 content 영역의 너비만 400px이 되고, 여기에 paddingborder를 감안하면 450px이 되기 때문입니다.

box-sizing 속성은 width 속성 뿐만 아니라 height 속성에도 동일한 영향을 줍니다. height 속성값이 30px이었는데, 여기서 상하 padding과 상하 border 두께를 빼면 -10px이 됩니다.

30px - (20px * 2) - (5px * 2) = -10px (?)

높이에는 음수 개념이 없기 때문에, content 영역의 높이는 0으로 취급되고, 아래 부분 padding이 짤리는 현상이 발생하게 됩니다. 따라서 height 속성값을 적당히 늘려줘야 하는데, 80px로 늘려주면 content 영역을 위한 가용 높이를 30px이 확보되어 이 전과 동일한 높이감을 가질 수 있습니다.

80px - (20px * 2) - (5px * 2) = 30x (!)
.box {
  box-sizing: border-box;
  width: 400px; /* 100% */
  height: 80px;
  /* 나머지 동일 */
}

기존에 직접 계산해야했던 content 영역의 너비와 높이를 자동으로 처리해주기 때문에 레이아웃이 많이 편해졌습니다. 실제 웹 프로젝트에서는 다음과 같이 전체 선택자로 아예 box-sizing 속성의 기본값을 바꾸는 경우도 어렵지 않게 볼 수 있습니다.

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

마치면서

지금까지 CSS에서 박스 모델의 개념과 box-sizing 속성을 이용해서 좀 더 편하게 레이아웃을 하는 방법에 대해서 간단히 알아보았습니다. 대부분 브라우저의 개발자 도구는 이 박스 모델의 각 층 별로 CSS 속성 값들이 어떻게 설정/계산되었는지를 시각적으로 보여줍니다. 따라서 그냥 웹페이지만 눈으로만 보시지 마시고, 개발자 도구를 통해 박스 모델을 정밀하게 분석해보시면 큰 도움이 되실 겁니다.

참고