Skip to content
This page has been auto-translated and may contain errors.View in English

박스 모델

docs.scrimba.com

CSS로 요소들의 간격을 맞추기 시작하면 모두가 마주치는 같은 문제를 만나게 됩니다: 너비를 설정하고 패딩을 추가했는데 요소가 요청한 것보다 더 넓어집니다. 두 단락이 숫자가 나타내는 것보다 더 가까이 앉아있습니다. 이 모든 것이 버그는 아닙니다. 이것이 박스 모델로, 모든 요소가 차지하는 공간의 양을 결정하는 규칙 집합이며, 이를 시각화할 수 있으면 대부분의 간격 관련 놀라움은 더 이상 놀라움이 아닙니다.

모든 요소는 박스입니다

CSS는 페이지의 모든 요소를 직사각형으로 취급합니다. 단 한 단어나 링크도 마찬가지입니다. 그 직사각형은 안쪽에서 바깥쪽으로 쌓인 4개의 레이어로 만들어지며, 이것이 **박스 모델**입니다: 중간의 콘텐츠, 그 주위의 패딩, 테두리, 그리고 바깥쪽의 여백입니다.

벽에 걸린 액자 사진을 생각해보세요. 사진이 콘텐츠입니다. 사진 주위의 흰색 매트가 패딩으로, 액자 안의 숨 쉴 공간입니다. 나무로 된 액자 자체가 테두리입니다. 그리고 이 액자와 다음 액자 사이의 빈 벽이 여백입니다. 스타일을 지정하는 모든 요소는 안쪽에서 바깥쪽으로 같은 방식으로 패키징됩니다.

css
.card {
  padding: 16px;              /* 안쪽 공간, 콘텐츠 주위 */
  border: 2px solid #333;     /* 액자 */
  margin: 24px;               /* 바깥쪽 공간, 이웃 요소를 밀어냄 */
}

브라우저가 렌더링하는 모든 요소는 직사각형 박스이며, 그 박스는 중심에서 바깥쪽으로 측정되는 4개의 부분을 가집니다: 콘텐츠 박스(텍스트나 이미지가 있는 곳), 패딩, 테두리, 여백. 이 개념은 이미 CSS 작동 방식에서 보았습니다. 박스 모델은 크기와 간격을 제어하는 부분입니다.

순서가 중요한 이유는 각 레이어가 그 앞의 레이어를 감싸기 때문입니다. 패딩은 콘텐츠와 테두리 사이에 있으므로 배경색은 콘텐츠와 패딩을 채우지만 테두리의 바깥쪽 끝에서 멈춥니다. 여백은 테두리 바깥에 있으며 항상 투명하므로 여백에 색을 지정할 수 없습니다.

css
.card {
  padding: 16px;              /* 테두리 안쪽, 배경을 공유 */
  border: 2px solid #333;
  margin: 24px;              /* 테두리 바깥쪽, 항상 투명 */
  background: #f4f4f4;       /* 콘텐츠 + 패딩을 채우고, 테두리에서 멈춤 */
}

모든 렌더링된 요소는 최소한 하나의 직사각형 **박스**를 생성하며, 박스 모델은 4개의 중첩된 영역의 명세입니다. 안쪽에서 바깥쪽으로: 콘텐츠 박스(요소의 텍스트, 이미지 또는 자식 박스를 담는 영역), 패딩 박스(콘텐츠에 패딩을 더한 것, 요소의 배경을 여전히 전달하는 투명한 공간), 테두리 박스(패딩 박스에 테두리를 더한 것, 보이는 가장자리), 여백 박스(테두리 박스에 여백을 더한 것, 요소를 이웃으로부터 분리하는 가장 바깥쪽 투명 영역).

이 중첩에서 나오는 두 가지 결과가 나중에 사람들을 혼란스럽게 합니다. 첫째, 배경은 여백 박스가 아닌 패딩 박스를 칠하므로 패딩은 클릭 가능하고 색칠할 수 있는 내부 공간을 제공하는 반면 여백은 스타일을 지정할 수 없는 빈 분리를 제공합니다. 둘째, 선언한 너비와 높이는 기본적으로 전체 박스를 설명하지 않습니다. 박스의 한 영역만 설명하며, 어느 영역인지는 box-sizing에 달려있으며, 다음 섹션에서 이를 명확히 합니다.

css
.card {
  padding: 16px;
  border: 2px solid #333;
  margin: 24px;
  background: #f4f4f4;       /* 콘텐츠 + 패딩을 칠하고, 절대 여백은 아님 */
}
Juno모든 요소는 박스입니다 모든 요소는 안쪽에서 바깥쪽으로 4개의 레이어를 가진 박스입니다: 콘텐츠, 패딩, 테두리, 여백. 액자 사진 비유가 나에게 와닿았습니다: 사진, 매트, 액자, 다음 액자까지의 간격. 이 그림을 머릿속에 얹으면 이 장의 나머지 부분이 따라옵니다.
Juno모든 요소는 박스입니다 콘텐츠, 패딩, 테두리, 여백이 바깥쪽으로 감싸집니다. 배경은 콘텐츠와 패딩을 채우고 테두리에서 멈추며, 여백은 항상 투명하므로 margin은 색을 받지 않습니다. 중첩을 직선으로 유지하면 간격 규칙은 더 이상 자의적으로 느껴지지 않습니다.
Juno모든 요소는 박스입니다 4개의 중첩된 영역: 콘텐츠 박스, 패딩 박스, 테두리 박스, 여백 박스. 배경은 테두리 박스까지 칠하고 절대 여백을 칠하지 않으므로 패딩은 색칠할 수 있는 내부이고 여백은 빈 분리입니다. 그리고 선언한 width는 항상 이 영역 중 하나만 크기를 조정하며, 이것이 다음 섹션의 box-sizing이 존재하는 전체 이유입니다.

padding, border, 그리고 margin

3개의 간격 레이어는 각각 하나의 일을 합니다. **패딩**은 콘텐츠와 테두리 사이의 안쪽 공간입니다. 여백은 바깥쪽 공간이며 다른 요소를 밀어냅니다. 테두리는 그들 사이에 그려진 선입니다.

한 번에 4개의 모든 변에 대해 하나의 값을 설정하거나 한쪽 면을 대상으로 지정할 수 있습니다:

css
.card {
  padding: 20px;             /* 4개의 모든 변이 20px를 받음 */
  margin-bottom: 32px;       /* 아래쪽 끝만 */
}

padding: 20px 축약형은 위, 오른쪽, 아래, 왼쪽을 모두 함께 말하는 빠른 방법입니다. 한쪽이 나머지와 다를 필요가 있을 때는 margin-bottom처럼 구체적인 속성을 사용하세요.

**패딩**은 테두리 안의 공간이고, 여백은 테두리 바깥의 공간이며, 테두리는 그들 사이의 가장자리입니다. 유지할 규칙은 여백은 이웃을 밀어내고, 패딩은 요소 자신의 내부를 키운다는 것입니다. 배경이 텍스트에 밀착되어 보인다면 패딩의 일입니다. 두 요소가 너무 가까우면 여백의 일입니다.

각각은 위부터 시계방향으로 변을 채우는 축약형을 사용합니다. 하나의 값은 4개의 변 모두에 적용되고, 두 개의 값은 수직 다음 수평을 설정하며, 4개의 값은 위, 오른쪽, 아래, 왼쪽입니다:

css
.hero {
  padding: 40px 24px;        /* 위아래 40px, 좌우 24px */
  margin: 0 auto;            /* 수직 여백 없음, 좌우 auto로 중앙 배치 */
}

.card {
  padding-left: 16px;        /* 한쪽 끝만 다를 때 변별 지정 */
}

패딩, 테두리, 여백은 같은 간격의 3가지 이름이 아닌 3가지 독립적인 간격 제어로 다른 동작을 합니다. 패딩은 테두리 안의 투명한 영역이지만 여전히 배경을 전달하고 클릭에 반응합니다. 여백은 테두리 바깥의 투명한 영역이며 요소를 형제 요소로부터 분리하고 배경을 전달하지 않습니다. 테두리는 그려진 가장자리이며 또한 그 너비와 같은 레이아웃 공간을 차지합니다.

3가지 모두 시계방향 축약형(1개, 2개, 3개 또는 4개의 값이 위/오른쪽/아래/왼쪽으로 확장)을 허용하며, 3가지 모두 변별 긴 형태를 가집니다. 정확히 보유할 가치가 있는 2가지 동작이 있습니다. 여백은 음수일 수 있으며, 이는 요소를 이웃 쪽으로 끌어당기거나 위로 이동시키고 합법적인 레이아웃 도구이지만, 패딩은 0 아래로 갈 수 없습니다. 그리고 margin: 0 auto는 요소가 확정된 너비를 가질 때만 블록을 수평으로 중앙 배치합니다. 왜냐하면 auto는 남은 수평 공간을 분할하여 확인되고, 박스가 이미 컨테이너를 채우면 분할할 남은 공간이 없기 때문입니다.

css
.hero {
  padding: 40px 24px;        /* 시계방향 쌍: 수직, 수평 */
  margin: 0 auto;            /* .hero에 설정된 너비로만 중앙 배치 */
  border-bottom: 1px solid #ddd;  /* 테두리 긴 형태, 한쪽 끝, 레이아웃에서 1px를 차지 */
}

.card {
  margin-top: -8px;          /* 음수 여백은 카드를 위로 끌어당김 */
}
Junopadding, border, 그리고 margin 패딩은 테두리 안의 공간이고, 여백은 테두리 바깥의 공간이며, 테두리는 그들 사이의 선입니다. 텍스트가 박스 안에서 밀착되어 보일 때 padding을 사용하고, 두 박스가 너무 가까울 때 margin을 사용하세요. padding: 20px같은 하나의 값은 4개의 모든 변을 포함하고, 한쪽만 바뀔 필요가 있을 때 margin-bottom처럼 이름을 지정하세요.
Junopadding, border, 그리고 margin 패딩은 요소 자신의 내부를 키우고, 여백은 이웃을 밀어내며, 어느 것을 원하는지 아는 것은 많은 추측을 저장합니다. 축약형은 위부터 시계방향으로 실행됩니다: 모든 변에 1개의 값, 수직 다음 수평에 2개. 배경이 텍스트에 너무 밀착되면 여백이 아닌 패딩이 필요합니다.
Junopadding, border, 그리고 margin 패딩은 배경과 클릭을 전달하고, 여백은 투명한 분리이며, 테두리는 그 너비와 같은 실제 레이아웃 공간을 차지합니다. 여백은 음수로 갈 수 있어 요소를 함께 끌어당기고, 패딩은 할 수 없습니다. 그리고 margin: 0 auto는 확정된 너비를 가진 블록만 중앙 배치합니다. 왜냐하면 그렇지 않으면 auto가 분할할 남은 공간이 없기 때문입니다.

box-sizing: content-box vs border-box

거의 모두를 당황하게 하는 놀라움이 여기 있습니다. 카드를 width: 300px로 설정하고 패딩을 추가하면 카드가 페이지에서 300픽셀보다 더 넓어집니다. 당신은 잘못된 것을 하지 않았습니다. 기본적으로 width는 중간의 콘텐츠만 측정하며 패딩과 테두리는 그 위에 추가됩니다.

너비가 예상한 방식으로 작동하게 하는 한 줄의 수정이 있습니다. box-sizing: border-box를 설정하면 이제 입력한 너비는 박스의 전체 너비이며 패딩과 테두리가 포함됩니다:

css
.card {
  box-sizing: border-box;    /* 너비에 이제 패딩과 테두리가 포함됨 */
  width: 300px;
  padding: 20px;             /* 카드는 340px가 아닌 300px로 유지됨 */
}

기본적으로 모든 요소는 box-sizing: content-box를 사용하며, 이는 설정한 width가 콘텐츠 박스에만 적용된다는 의미입니다. 그 다음 패딩과 테두리가 추가되므로 페이지에서 실제로 보이는 박스는 입력한 숫자보다 넓습니다. 이것이 수백 개의 폭발된 레이아웃 뒤의 고전적인 크기 조정 함정입니다.

한 번 수학을 하면 명확합니다. content-box로, 300px 너비에 각 변에 20px 패딩과 각 변에 2px 테두리를 더하면 300 + 40 + 4 = 344px로 렌더링됩니다. **border-box**로 전환하면 이제 width는 테두리 박스를 의미합니다: 패딩과 테두리는 안쪽에서 빼지므로 요소는 정확히 300px로 유지되고 콘텐츠는 맞도록 축소됩니다.

css
.card {
  box-sizing: content-box;   /* 기본값 */
  width: 300px;
  padding: 20px;
  border: 2px solid #333;
  /* 실제 렌더링된 너비: 300 + 20 + 20 + 2 + 2 = 344px */
}

이것이 거의 항상 당신이 원하는 것이기 때문에, 표준 이동은 보편 선택자를 사용해 전역적으로 설정하여 모든 요소가 선택하게 하는 것입니다:

css
* {
  box-sizing: border-box;    /* 한 규칙, 어디서나 예측 가능한 크기 조정 */
}

box-sizingwidthheight가 어느 영역을 측정하는지 결정하며 2개의 값을 가집니다. 초기값은 content-box입니다: width는 콘텐츠 박스를 설정하고 패딩과 테두리는 그 너비 바깥에 배치되므로 테두리 박스, 페이지 위의 실제 발자국은 width + padding-left + padding-right + border-left + border-right입니다. 대안은 **border-box**입니다: width는 테두리 박스를 직접 설정하고 브라우저는 패딩과 테두리를 안쪽에서 뺀 후 콘텐츠 박스를 남은 것으로 축소합니다.

산술은 정확히 표시할 가치가 있으며, 그것이 속성이 존재하는 전체 이유입니다. width: 300px; padding: 20px; border: 2px가 주어지면:

css
/* content-box (기본값): 패딩과 테두리가 위에 추가됨 */
.card {
  box-sizing: content-box;
  width: 300px;
  padding: 20px;
  border: 2px solid #333;
  /* 테두리 박스 = 300 + 40 + 4 = 344px; 콘텐츠 박스 = 300px */
}

/* border-box: 패딩과 테두리가 선언된 너비를 먹음 */
.card {
  box-sizing: border-box;
  width: 300px;
  padding: 20px;
  border: 2px solid #333;
  /* 테두리 박스 = 300px; 콘텐츠 박스 = 300 - 40 - 4 = 256px */
}

border-box를 권장합니다: 크기 조정을 합성 가능하게 만듭니다. 이유는 실용적입니다: border-box로, width: 25%에서 선언된 열 집합은 패딩을 추가해도 컨테이너의 1/4에 유지됩니다. 왜냐하면 패딩은 더 이상 바깥쪽 크기를 바꾸지 않기 때문입니다. 그 예측 가능성이 거의 보편적인 리셋이 의사 요소를 포함하여 모든 것에 적용하는 이유이므로 아무것도 content-box로 조용히 돌아가지 않습니다:

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

한 가지 정밀도 주의: 이것은 widthheight만 제어합니다. 여백은 box-sizing에 관계없이 항상 테두리 박스 바깥에 있으므로 선언된 크기에 계산되지 않으므로 아래의 여백 겹침과 직접 연결됩니다. 이 박스들을 안정적으로 크기 조정하려면 단위가 필요하면 크기 조정 단위는 백분율, rem, 뷰포트 단위가 어떻게 확인되는지를 다룹니다.

Junobox-sizing: content-box vs border-box 기본적으로, 설정한 width는 중간의 콘텐츠만 측정하므로 패딩과 테두리는 박스를 입력한 숫자보다 더 크게 만듭니다. box-sizing: border-box를 설정하면 수정됩니다: 너비는 전체 박스, 패딩과 테두리가 포함됩니다. 이것이 오랫동안 나를 당황하게 했으므로 일찍 기억하는 것이 좋습니다.
Junobox-sizing: content-box vs border-box 기본값 content-boxwidth가 콘텐츠만 크기 조정한다는 의미이므로 패딩과 테두리는 요청한 것보다 실제 박스를 더 넓게 밀어냅니다. 20px 패딩과 2px 테두리가 있는 300px 카드는 실제로 344px로 렌더링됩니다. border-box로 전환하면 너비는 전체 박스를 의미하므로 대부분의 스타일시트의 첫 번째 줄로 *에 설정하는 것이 표준입니다.
Junobox-sizing: content-box vs border-boxcontent-box는 너비 바깥에 패딩과 테두리를 추가하므로 300px 박스는 344px가 되고; border-box는 안쪽에서 빼고 300px에 유지합니다. 패딩이 더 이상 바깥쪽 크기를 바꾸지 않을 때 백분율 너비가 합성 가능하게 유지되므로 border-box에 도달합니다. * 및 의사 요소에 적용하여 아무것도 조용히 기본값으로 돌아가지 않게 하세요.

여백 겹침

한 가지 더 놀라움이 있으며 여백 쌓임에 관한 것입니다. 두 단락을 위아래로 놓고 첫 번째에 24px 아래쪽 여백을, 두 번째에 16px 위쪽 여백을 주면 그들 사이에 40px의 간격을 기대할 수 있습니다. 실제로는 24px를 얻습니다.

이것을 **여백 겹침**이라고 합니다. 두 수직 여백이 만날 때, 브라우저는 그들을 함께 더하지 않습니다. 더 큰 것을 유지하고 더 작은 것을 버립니다. 따라서 더 큰 여백이 이기고 간격은 40px이 아닌 24px입니다. 패딩에서는 절대 일어나지 않으며 위/아래 여백에만 발생합니다.

css
.intro {
  margin-bottom: 24px;
}
.details {
  margin-top: 16px;
  /* 그들 사이의 간격은 24px, 40px이 아님 */
}

한 블록의 아래쪽 여백이 다음 블록의 위쪽 여백을 만날 때, 둘은 더해지지 않습니다. 둘의 더 큰 것과 같은 단일 여백으로 겹칩니다. 한 단락에 margin-bottom: 24px를 주고 다음에 margin-top: 16px을 주면 그들 사이의 공간은 40px이 아닌 24px입니다. 이것이 **여백 겹침**이며 수직 여백에만 영향을 미칩니다.

이것을 아는 이유는 간격에 대해 추론하는 방식을 바꾸기 때문입니다. 간격이 두 숫자가 제안하는 것보다 작으면 당신은 아마도 겹침을 보고 있으며 더 작은 여백에 추가해도 더 큰 여백을 통과할 때까지 아무것도 하지 않습니다. 수직 리듬을 제어하는 깨끗한 방법은 한 방향으로만 여백을 설정하는 것입니다. 예를 들어 모든 블록에 margin-bottom을 설정하고 margin-top은 설정하지 않으므로 겹침이 확인할 것이 없습니다.

css
.article > * {
  margin-top: 0;
  margin-bottom: 24px;       /* 한 방향, 그래서 간격은 예측 가능 */
}

**여백 겹침**은 일반 흐름에서 인접한 수직 여백이 하나로 합쳐지는 규칙이며 그 크기는 둘 중 더 큰 것입니다(또는 가장 양수, 음수는 가장 큰 양수와 가장 음수를 합산하여 처리). 일반 흐름은 어떤 flex, grid 또는 float이 이를 바꾸기 전의 기본 위에서 아래로의 블록 박스 쌓임입니다. .intro24px 아래쪽 여백을 주고 .details16px 위쪽 여백을 주면 간격은 24px입니다. 왜냐하면 브라우저는 둘을 단일 겹친 여백으로 확인하기 때문입니다.

정밀한 부분은 무엇이 겹치고 무엇이 겹치지 않는지 아는 것입니다. 왜냐하면 탈출은 놀라움을 멈추는 방법이기 때문입니다:

  • 수직 여백에만 영향을 미칩니다. 수평 여백은 절대 겹치지 않습니다. 나란히 앉은 두 요소는 항상 그들의 마주하는 여백을 더합니다.
  • 두 여백 사이의 모든 것이 겹침을 멈춥니다: 테두리, 패딩, 또는 자식 여백과 그 자신 사이의 부모에 있는 콘텐츠.
  • 여백은 포맷팅 컨텍스트 경계를 넘어 겹치지 않습니다. flex 또는 grid 컨테이너는 자식에 대해 하나를 수립하므로 그 안의 항목은 절대 그들의 여백을 겹치지 않습니다. 이것이 최신 레이아웃이 float 시대 것보다 더 예측 가능하게 느껴지는 한 가지 이유입니다.
  • 부모와 그 첫 또는 마지막 자식은 아무것도 그들을 분리하지 않을 때 서로 관통 겹칠 수 있습니다. 따라서 자식의 위쪽 여백은 예상치 못하게 부모 밖에 나타날 수 있습니다. 부모에 padding-top 또는 테두리를 추가하면 멈춥니다.
css
/* 겹침이 발생함: 일반 흐름에서 인접한 형제 */
.intro { margin-bottom: 24px; }
.details { margin-top: 16px; }   /* 간격은 24px로 확인됨 */

/* 겹침 멈춤: 여백 사이의 테두리 */
.section {
  border-top: 1px solid #eee;    /* 이제 둘 다 적용되고, 합병하지 않음 */
}
Juno여백 겹침 아래쪽 여백이 위쪽 여백을 만날 때, 브라우저는 더 큰 것을 유지하고 더 작은 것을 버립니다. 그들을 추가하는 대신 24px 아래가 16px 위를 만나면 40px이 아닌 24px 간격을 얻습니다. 위/아래 여백에만 발생하며 처음에 모두를 놀라게 합니다.
Juno여백 겹침 블록 사이의 수직 여백은 합이 아닌 더 큰 값으로 겹치므로 간격은 숫자가 제안하는 것보다 작을 수 있습니다. 그럴 때 더 작은 여백을 키워도 더 큰 것을 초과할 때까지 아무것도 하지 않습니다. 한 방향으로만 여백을 설정하면, 예를 들어 모든 블록에 margin-bottom을 설정하면 전체 일을 우회합니다.
Juno여백 겹침 일반 흐름의 인접한 수직 여백은 더 큰 값으로 합쳐지고, 수평 여백은 절대 합쳐지지 않습니다. 그들 사이의 테두리 또는 패딩은 겹침을 멈추고, flex 및 grid 컨테이너는 완전히 멈춥니다. 자식의 위쪽 여백이 부모에 padding-top 또는 테두리를 추가할 때까지 부모를 탈출하는 부모 및 첫 자식 경우를 주시하세요.