CSS width: 100%에 마진을 더하면 왜 넘칠까?

부모 폭은 320px인데 카드에 양쪽 여백을 주자 가로로 삐져나온다. box-sizing: border-box까지 지정했는데, 카드 폭은 어떻게 잡아야 넘치지 않을까?

CSS width: 100%에 마진을 더하면 왜 넘칠까?
세 줄 요약
  • width: 100%와 border-box를 함께 써도 margin은 지정한 폭 밖에 남는다.
  • width: stretch는 마진 박스가 가용 폭에 맞도록 크기를 계산하며 Safari 27도 지원한다.
  • 일반 블록은 auto로 충분할 수 있다. 최소 폭과 긴 문자열 때문에 생기는 넘침은 따로 살펴야 한다.

border-box는 마진을 폭 안으로 넣지 않는다

width: 100%인 카드에 좌우 마진을 더하면 부모 폭을 넘을 수 있다. box-sizing: border-box도 이 마진을 포함하지 않기 때문이다. box-sizing의 계산 범위는 콘텐츠·패딩·테두리까지이며, 바깥 여백은 그 밖에 놓인다.

예를 들어 부모의 콘텐츠 폭이 320px라면 100%인 카드의 테두리 바깥까지가 이미 320px다. 여기에 왼쪽 16px, 오른쪽 16px의 여백을 모두 확보하려면 더 넓은 공간이 필요하다. padding을 줄이는 것만으로는 이 계산이 바뀌지 않는다.

Safari 27이 추가한 stretch 크기 지정은 이런 경우에 쓸 수 있다. width: stretch는 마진까지 포함한 박스를 가용 폭에 맞추려는 값이다.

100%는 320px, stretch는 마진을 남긴 288px

다음은 일반 블록 카드의 폭을 계산하는 예시다. 부모의 콘텐츠 폭은 320px이고, 별도의 최소·최대 폭 제한은 없다고 가정한다.

.parent { width: 320px; }
.card {
  box-sizing: border-box;
  margin-inline: 16px;
  padding: 12px;
  border: 2px solid;
  width: 100%;
}
width 값테두리까지의 폭콘텐츠 폭좌우 16px 여백
100%320px292px부모 폭 안에 함께 들어가지 않는다.
stretch288px260px부모 폭 안에 들어간다.
auto288px260px이 일반 블록 예시에서는 들어간다.

stretch의 기준은 마진 박스다. 320px에서 좌우 마진 32px를 빼면 테두리까지 288px가 남는다. 여기에서 패딩 24px와 테두리 4px를 빼면 실제 콘텐츠 폭은 260px다. 100%인 경우에는 테두리까지의 320px에서 패딩과 테두리만 빼므로 콘텐츠가 292px다.

일반 블록이라면 먼저 width: auto를 검토한다

카드가 일반 문서 흐름의 블록 요소라면 width: 100%를 없애거나 auto로 바꾸는 것으로 충분할 수 있다. 일반 블록의 폭 계산은 지정한 여백과 테두리·패딩을 반영해 남는 폭을 채운다. 위 표에서 auto와 stretch의 결과가 같은 이유다.

이를 이미지나 inline-block, 모든 Flexbox 문맥에 그대로 적용할 수는 없다. auto가 무엇을 뜻하는지는 요소와 배치 방식에 따라 달라진다. 명시적으로 마진 박스를 가용 폭에 맞춰야 할 때 stretch를 선택한다.

일반 블록 카드에 점진적으로 적용한다면, @supports로 해당 선언의 지원 여부를 나눌 수 있다.

.card { width: auto; }

@supports (width: stretch) {
  .card { width: stretch; }
}

이미 auto로 원하는 배치가 나온다면 이 분기를 추가할 필요도 없다. 기존 레이아웃에서 auto가 다른 크기를 만드는 요소라면 그 요소에 맞는 대체 값을 먼저 마련해야 한다.

긴 URL과 최소 폭은 별도의 문제다

stretch는 넘치는 모든 콘텐츠를 줄이는 명령이 아니다. CSS 크기 규격에서도 stretch 계산은 min-width·max-width 등의 제약을 따른다. 부모보다 큰 최소 폭을 지정해 놓았다면 width 값 하나를 바꿔도 그 조건이 남는다.

카드 자체는 들어가는데 긴 URL만 삐져나온다면 텍스트의 줄바꿈을 살펴야 한다. overflow-wrap: anywhere는 다른 줄바꿈 지점이 없는 긴 문자열을 나눌 수 있게 한다. 먼저 카드의 테두리가 넘치는지, 안쪽 내용만 넘치는지 구별하면 폭 계산과 콘텐츠 처리 중 무엇을 고쳐야 할지 정할 수 있다.