블록의 top 및 bottom 마진은 때로는 (결합되는 마진 중 크기가) 가장 큰 한 마진으로 결합(combine, 상쇄(collapsed)) 됩니다, 마진 상쇄(margin collapsing)로 알려진 행동
마진 상쇄는 요소들이 세로로 배치되어 있을 경우에 발생한다. 마진 상쇄

이미지를 보면 요소 A의 margin-bottom: 10px 이고 요소 B의 margin-top: 30px이다. 요소 B의 마진이 요소 A의 마진보다 값이 크다.
이렇게 위아래로 겹쳐진 요소 간의 top과 bottom의 마진이 모두 존재할 때 더 큰 값만 적용되고 작은 값은 무시된다. 이 현상을 상쇄된다고 표현한다.
그래서 결과물은 이미지의 화살표 오른쪽처럼 30px만 적용되는 것이다.
만약 50px, 20px가 아니라 30px, 30px라면 하나만 렌더링 된다.
좌우 여백은 해당되지 않는다.

국어사전을 보면 상쇄된다는 말은 효과가 없어지는 것을 말한다.
마진의 효과는 화면에 렌더링 되는 것이니까 상쇄된 더 작은 마진은 화면에 나타나지 않는다. 하지만 지정된 값 자체가 없어지는 것은 아니다.
<h1>Heading 1</h1>
<h2>Heading 2</h2>
h1 {
margin: 0 0 50px 0;
background-color: red;
}
h2 {
margin: 20px 0 0 0;
background-color: blue;
}

위 이미지는 파란색 요소의 margin-top:20px가 상쇄된 상태다. 현재 사이 여백은 50px이다.

보면 빨간색 요소의 margin-bottom이 마진 여백(주황색 부분)을 다 채우는 것을 확인할 수 있다.

그런데 파란색 요소를 확인하면 margin-top 영역이 존재한다. 여백이 상쇄된 것이지 없어진 것이 아니다.
위에서 예시로 든 상황이 바로 이 상황이다.
빈 요소
- 높이(height)가 0인 상태의 블록 요소
- 요소의 크기가 상하로 늘어나는 프로퍼티 값이 없을 때
- height
- min-height / max-height
- padding
- border 등
- 내부에 inline 콘텐츠가 존재하지 않는 요소

빈 요소의 경우 위와 아래를 가르는 경계가 없다는 말이 이해가 안 가서 그림을 만들어봤다.
이렇게 빈 요소의 경우는 위아래를 구분할 수 없어서 자신의 margin-top, margin-bottom을 비교하고 마진 상쇄가 발생한다.
빈 요소가 사용되는 경우
- 빠른 레이아웃 구성을 위해 div로 영역을 만들어 놓을 경우
- 내부에 요소를 append 하기 위해 빈 컨테이너를 만들어 놓을 경우 등
(height, padding, border 등 높이와 관련된 속성들은 상위로부터 상속되지 않는다.)
부모 박스와 첫 번째 자식의 margin-top, 마지막 자식의 margin-bottom이 겹칠 때 발생한다.
* {
margin: 0;
padding: 0;
}
body {
background-color: #eee;
padding: 0 30px;
}
.parent {
background-color: green;
margin: 30px 0;
}
.red {
width: 300px;
height: 100px;
background-color: red;
margin-top: 20px;
}
.blue {
width: 300px;
height: 100px;
background-color: blue;
margin-bottom: 20px;
}
<div class="parent">
<div class="red">red</div>
<div class="blue">blue</div>
</div>
예제를 만들어봤다.
margin: 30px 0margin-top: 20pxmargin-bottom: 20px
개발자 도구로 확인해 보면,

parent인 초록색 박스의 margin:30px 0이 적용되어 있다. 각 주황색 부분이 30px이다.

빨간색 박스의 margin-top:20px도 여전히 존재한다. 상쇄되어 렌더링 되지 않을 뿐이다.

파란색 박스의 margin-bottom: 20px도 여전히 존재한다. 상쇄되어 렌더링 되지 않을 뿐이다.
이 경우 자식 요소의 마진 값이 살아남더라도 부모 요소에 마진이 적용된 것처럼 보이게 된다.
마진이란 콘텐츠 간의 간격이고, 간격을 벌리기 위해서는 경계를 필요로 합니다. 브라우저는 부모 박스와 첫 번째(마지막) 자식 박스 간의 경계를 그 사이에 있는 border / padding / inline 콘텐츠 유무로 판단합니다. 앞에 설명했던 빈 박스의 마진 상쇄 현상과는 조금 다르게, 이미 명시적으로 height / min-height 값을 줬더라도 이번 경우에선 신경 쓰지 않습니다. [CSS 마진 상쇄(Margin-collapsing) 원리 완벽 이해]
케이스를 나눠보니 경계를 인식할 수 있냐가 마진 상쇄가 발생하는 기준인 것 같다.
경계를 만들어 주는 것이 해결법이라고 하는데 padding을 주거나, border를 주거나, 사이에 인라인 요소를 삽입하거나 하는 해결법이 존재한다.