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

raram2·2019년 11월 23일
10

프론트엔드 개발

목록 보기
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로 일하고 있습니다

2개의 댓글

comment-user-thumbnail
2020년 7월 24일

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

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

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

답글 달기