CSS 마진 상쇄(Margin-collapsing) 원리 완벽 이해

Kimaramy·2019년 11월 23일
101

프론트엔드 개발

목록 보기
1/14
post-thumbnail

마진 상쇄란?

흔히 마진 겹침 현상이라고도 불립니다. (혹자는 '마진 빡침 현상'이라고도 합니다) 하지만 인과관계로 볼 때, 마진이 겹치게 되면 상쇄가 일어나기 때문에 영미권에서는 '마진 상쇄(Margin collapsing)'로 부르고 있습니다. 다음은 MDNW3C의 마진 상쇄에 대한 설명입니다.

블록의 top 및 bottom 마진은 때로는 (결합되는 마진 중 크기가) 가장 큰 한 마진으로 결합(combine, 상쇄(collapsed))됩니다, 마진 상쇄(margin collapsing)로 알려진 행동
-MDN

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
-W3C

쉽게 말해, 마진 상쇄는 어떤 두 개 이상 블록 요소의 상하 마진이 겹칠 때 어느 한 쪽의 값만 적용하는 브라우저 나름의 렌더링 규칙 정도로 이해하면 될 것 같습니다.

여기서부터는 블록(block) 요소를 편의상 박스라고 부르겠습니다.

마진 상쇄가 일어나는 3가지 상황

1. 인접 형제 박스 간 상하 마진이 겹칠 때

겹쳐진 두 마진 값을 비교해, 더 큰 마진 값으로 상쇄해 렌더링합니다. 만약 겹쳐진 두 값이 동일할 경우, 중복을 상쇄해 렌더링합니다.

2. 빈 요소의 상하 마진이 겹칠 때

'빈 요소' 란 높이(height)가 0인 상태의 블록 요소를 말합니다.

  • height / min-height / padding / border 등 상하로 늘어나는 프로퍼티 값을 명시적으로 주지 않았거나
  • 내부에 Inline 콘텐츠가 존재하지 않는 요소

이 경우 위와 아래를 가르는 경계가 없으므로, 자신의 상단 마진의 값과 하단 마진의 값을 비교해 더 큰 값으로 상쇄합니다. 만약 겹쳐진 두 값이 동일할 경우, 중복을 상쇄합니다. 특히 빈 요소와 인접 박스들 간에 마진 겹침이 일어나는 구조에서는 다음과 같이 상쇄가 여러 번 발생하게 됩니다.

"그럼 빈 요소를 안 만들면 되지 않나?"라고 생각하실지도 모르겠습니다. 하지만 마크업을 진행하다 보면 생각보다 많은 경우에 빈 요소를 만들어놓게 됩니다.

  • 빠른 레이아웃 구성을 위해 div로 영역을 만들어 놓을 경우
  • 내부에 요소를 append 하기 위해 빈 컨테이너를 만들어 놓을 경우 등

height, padding, border 등 높이와 관련된 속성들은 상위로부터 상속되지 않기 때문에, 위의 경우들을 위해서라도 꼭 인지해야 할 부분이라 생각합니다.

3. 부모 박스와 첫 번째(마지막) 자식 박스의 상단(하단) 마진이 겹칠 때

마진이란 콘텐츠 간의 간격이고, 간격을 벌리기 위해서는 경계를 필요로 합니다. 브라우저는 부모 박스와 첫 번째(마지막) 자식 박스 간의 경계를 그 사이에 있는 border / padding / inline 콘텐츠 유무로 판단합니다. 앞에 설명했던 빈 박스의 마진 상쇄 현상과는 조금 다르게, 이미 명시적으로 height / min-height 값을 줬더라도 이번 경우에선 신경 쓰지 않습니다.

따라서 부모와 첫 번째(마지막) 자식 사이에 inline 콘텐츠(텍스트 등)가 없거나, 상단(하단)에 명시적으로 padding 또는 border 값을 주지 않았다면 마진이 겹치게 됩니다. 이때, 자식 요소의 마진이 더 크든 작든 상관없이 상쇄된 마진은 부모 박스의 바깥으로만 렌더링이 됩니다. 😨

3-1. 부모 박스와 첫 번째 자식 박스의 상단 마진이 나란히 겹칠 때

3-2. 부모 박스와 마지막 자식 박스의 하단 마진이 나란히 겹칠 때

상단 마진끼리 겹칠 때와 같은 원리입니다. 예시 이미지 하나만 보겠습니다.

그래서

다음과 같이 부모 박스 상단(하단)에 padding 또는 border 값을 주어 벽을 만들어주는 것이 안전합니다. 이렇게 하면 의도했던 대로 첫 번째(마지막) 자식 요소를 배치할 수 있습니다.

마진 상쇄 규칙 적용

  • 마진 상쇄는 인접한 두 박스가 온전한 block-level 요소일 경우에만 적용됩니다.
    (inline, inline-block, table-cell, table-caption 등의 요소는 block-level이 아닙니다.)
  • 마진 값이 0이더라도 상쇄 규칙은 적용됩니다.
  • 좌우 마진은 겹치더라도 상쇄되지 않습니다.

마진 상쇄 규칙 예외

다음과 같은 상황에서는 인접 요소 간 마진 상쇄가 일어나지 않습니다.

  • 박스가 position: absolute 된 상태
  • 박스가 float: left/right 된 상태 (단, clear 되지 않은 상태)
  • 박스가 display: flex 일 때 내부 flexbox item
  • 박스가 display: grid 일 때 내부 grid item

마치며

이전에 저는 마진 값을 어찌어찌 바꿔보면서 의도한 대로 보이면 그냥 넘어간 경우가 많았습니다. 하지만 계속된 시행착오를 막고자 이번 기회에 정리를 해봤습니다. 이것저것 찾아보다 보니 제가 잘 안다고 생각했던 것들이 결국 얕은 수준이었다는 것을 깨닫게 됐습니다.😂 넓게 아는 것과 깊게 아는 것. 그 중간을 잘 맞춰가야겠습니다.

더 알아보기


profile
스타트업에서 Software Engineer로 일하고 있습니다

13개의 댓글

comment-user-thumbnail
2020년 7월 24일

도움이 됐습니다 감사해요!

답글 달기
comment-user-thumbnail
2020년 8월 1일

읽어본 글 중에서 가장 잘 정리된 글 이네요. 감사합니다.

답글 달기
comment-user-thumbnail
2021년 1월 9일

오픈 튜토리얼스에서 댓글보구 왔습니다.
정말 유익하게 잘 봤어요!

답글 달기
comment-user-thumbnail
2021년 1월 11일

너무 아름다운 글이예요
살포시 하트 누르고 갑니다

답글 달기
comment-user-thumbnail
2021년 3월 28일

제일 도움되는 글이었어요 ㅜㅜ 감사합니다!!!

답글 달기
comment-user-thumbnail
2021년 4월 15일

덕분에 잘 공부했어요, 감사합니다

답글 달기
comment-user-thumbnail
2021년 11월 4일

이거때문에 고생하고 있는데 도움 많이 됐어요! 감사합니다 ㅎㅎ

답글 달기
comment-user-thumbnail
2021년 12월 14일

정말 감사합니다! 이렇게 완벽하게 정리해주셔서 감사합니다.

답글 달기
comment-user-thumbnail
2022년 5월 23일

주로 flex 위주로 사용하면 큰 문제 없을듯. 잘보고 가요

답글 달기
comment-user-thumbnail
2022년 7월 4일

감사합니다. 잘 읽고 갑니다.. 🧡

답글 달기
comment-user-thumbnail
2023년 6월 13일

정말 감사합니다! 혹시 이미지 어떻게 만드신건지 알려주실 수 있을까요? 이해 잘 가게 이쁘게 정말 잘 만드신 것 같아요

답글 달기
comment-user-thumbnail
2023년 11월 7일

도움이 많이 되었습니다 감사합니다!!

답글 달기
comment-user-thumbnail
2024년 1월 5일

글도 이미지도 아름답네요. 덕분에 골치아프던 마진 병합에 대해서 이번기회에 깔끔하게 정리하게 되었습니다. 이해가 잘되었어요! 감사해요 :)

답글 달기