흔히 마진 겹침 현상이라고도 불립니다. (혹자는 '마진 빡침 현상'이라고도 합니다) 하지만 인과관계로 볼 때, 마진이 겹치게 되면 상쇄가 일어나기 때문에 영미권에서는 '마진 상쇄(Margin collapsing)'로 부르고 있습니다. 다음은 MDN 및 W3C의 마진 상쇄에 대한 설명입니다.
블록의 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) 요소를 편의상 박스라고 부르겠습니다.
겹쳐진 두 마진 값을 비교해, 더 큰 마진 값으로 상쇄해 렌더링합니다. 만약 겹쳐진 두 값이 동일할 경우, 중복을 상쇄해 렌더링합니다.
'빈 요소' 란 높이(height)가 0인 상태의 블록 요소를 말합니다.
이 경우 위와 아래를 가르는 경계가 없으므로, 자신의 상단 마진의 값과 하단 마진의 값을 비교해 더 큰 값으로 상쇄합니다. 만약 겹쳐진 두 값이 동일할 경우, 중복을 상쇄합니다. 특히 빈 요소와 인접 박스들 간에 마진 겹침이 일어나는 구조에서는 다음과 같이 상쇄가 여러 번 발생하게 됩니다.
"그럼 빈 요소를 안 만들면 되지 않나?"라고 생각하실지도 모르겠습니다. 하지만 마크업을 진행하다 보면 생각보다 많은 경우에 빈 요소를 만들어놓게 됩니다.
height, padding, border 등 높이와 관련된 속성들은 상위로부터 상속되지 않기 때문에, 위의 경우들을 위해서라도 꼭 인지해야 할 부분이라 생각합니다.
마진이란 콘텐츠 간의 간격이고, 간격을 벌리기 위해서는 경계를 필요로 합니다. 브라우저는 부모 박스와 첫 번째(마지막) 자식 박스 간의 경계를 그 사이에 있는 border / padding / inline 콘텐츠 유무로 판단합니다. 앞에 설명했던 빈 박스의 마진 상쇄 현상과는 조금 다르게, 이미 명시적으로 height / min-height 값을 줬더라도 이번 경우에선 신경 쓰지 않습니다.
따라서 부모와 첫 번째(마지막) 자식 사이에 inline 콘텐츠(텍스트 등)가 없거나, 상단(하단)에 명시적으로 padding 또는 border 값을 주지 않았다면 마진이 겹치게 됩니다. 이때, 자식 요소의 마진이 더 크든 작든 상관없이 상쇄된 마진은 부모 박스의 바깥으로만 렌더링이 됩니다. 😨
상단 마진끼리 겹칠 때와 같은 원리입니다. 예시 이미지 하나만 보겠습니다.
다음과 같이 부모 박스 상단(하단)에 padding 또는 border 값을 주어 벽을 만들어주는 것이 안전합니다. 이렇게 하면 의도했던 대로 첫 번째(마지막) 자식 요소를 배치할 수 있습니다.
다음과 같은 상황에서는 인접 요소 간 마진 상쇄가 일어나지 않습니다.
position: absolute
된 상태float: left/right
된 상태 (단, clear 되지 않은 상태)display: flex
일 때 내부 flexbox itemdisplay: grid
일 때 내부 grid item이전에 저는 마진 값을 어찌어찌 바꿔보면서 의도한 대로 보이면 그냥 넘어간 경우가 많았습니다. 하지만 계속된 시행착오를 막고자 이번 기회에 정리를 해봤습니다. 이것저것 찾아보다 보니 제가 잘 안다고 생각했던 것들이 결국 얕은 수준이었다는 것을 깨닫게 됐습니다.😂 넓게 아는 것과 깊게 아는 것. 그 중간을 잘 맞춰가야겠습니다.
도움이 됐습니다 감사해요!