
과제를 해결하다가 아래와 같은 상황을 마주했다.

이 당시 나의 CSS 코드는,
.contents {
background-color: #eaeaea;
}
.contents .section {
background-color: white;
width: auto;
padding: 20px;
margin: 20px 0;
background-repeat: no-repeat;
background-position: right 30px center;
}
분명히 section에 상하단 margin을 설정했는데 왜 그만큼 영역을 차지하지 않고 사라진걸까?
마진 병합, 마진 겹침, 마진 상쇄 등의 이름으로 불리며, 말 그대로 마진이 겹쳐서 합쳐지는 현상을 말한다. 아래 코드를 이용하면 위의 그림과 같은 현상을 확인할 수 있는데, Block A와 Block B에 동일한 margin을 부여했기 때문에 당연히 A와 B가 만나는 부분의 마진이 40px가 될 것 같지만, 사실은 20px의 마진이 생성된다는 것이다.
[HTML]
<div class="box">A</div>
<div class="box">B</div>
[CSS]
.box {
width: 400px
height: 80px;
margin: 20px auto;
background-color: yellow;
}
여러 블록의 위쪽 및 아래쪽 마진은 경우에 따라 제일 큰 마진의 크기를 가진 단일 마진으로 결합(상쇄)되곤 합니다. 이런 동작을 마진 상쇄라고 부릅니다.
마진 병합 현상이 일어날 수 있는 조건은 두 가지로, 다음과 같다.
마진 병합 현상은 다음과 같은 세 가지 경우에 발생한다.
인접 형제 요소간의 상하 마진은 병합되는데, 겹쳐진 두 마진 값을 비교해, 더 큰 마진 값으로 병합된다.

테두리, 안쪽 여백, inline 콘텐츠, height, min-height, max-height가 없으면 블록의 margin-top과 margin-bottom이 서로 상쇄됩니다.

부모 블록에 border, padding, inline 요소가 없고, 부모의 margin-top, margin-bottom 을 자손의 margin-top 또는 margin-bottom과 분리할 권한이 없는 경우 부모와 자손의 마진이 병합된다. 병합된 마진은 부모 블록 바깥에 위치한다.

마진 병합 현상은 block 요소일 때만 발생한다는 조건에 위배되므로, block 요소의 display property를 inline-block 으로 변경한다면 마진 병합 현상을 해결할 수는 있다. 다만 inline 속성에 의해 baseline 기준으로 정렬되어 이를 해결해야 한다는 번거로움이 있을 것 같다.
부모 요소에 border 값을 설정하면, border 가 영역을 차지하므로 경계가 생기고, 이 경계를 기준으로 마진 값이 나뉘게 되어 마진 병합 현상을 해결할 수 있다. 하지만 border 역시 영역을 차지하게 되기 때문에, 의도한대로 스타일링을 하는데 번거로움이 있을 수 있다고 생각한다.
.wrapper {
width: 400px;
margin: 20px auto;
border: 1px solid red;
}
.box {
height: 80px;
margin: 20px auto;
background-color: white;
}

border 와 마찬가지로 부모 요소에 padding 값을 설정하면, padding이 부모 요소 내부의 영역을 차지하므로 마진 값을 나누는 경계가 되어 마진 병합 현상을 해결할 수 있다. 이 방법이 스타일링 하기에 내게 가장 익숙하면서 간단한 수치 계산만 해 주면 되기에 쉬운 방법이라고 생각했고, 멘토님께서도 실무에서 상단 padding, 하단 margin 값을 부여하여 마진 병합 현상 없이 관리하는 경우가 많다고 말씀하셨다.
.wrapper {
width: 400px;
margin: 20px auto;
padding: 20px 0;
}
.box {
height: 80px;
margin: 20px auto;
background-color: white;
}

최상위 (root) 요소인 html은 마진 병합 현상의 영향을 받지 않기 때문에, 부모 요소의 display 속성을 flow-root로 변경함으로써 마진 겹침 현상을 해결할 수 있다. 다만 이는 형제 요소 간의 마진 병합 현상을 해결할 수는 없으며, Internet Explorer에서는 해당 속성이 적용되지 않기 때문에 주로 사용하지는 않는다.
.wrapper {
width: 400px;
margin: 20px auto;
display: flow-root;
}
.box {
height: 80px;
margin: 20px auto;
background-color: white;
}

부모 요소에 height를 지정하면 자식 요소가 부모 요소의 크기보다 커져 영역을 넘어서는 overflow 현상이 발생할 수 있는데, overflow property를 scroll 또는 hidden으로 설정하면 부모 요소가 자식 요소의 마진을 수용할 수 있게 되어 마진 병합 현상을 해결할 수 있다.
.wrapper {
width: 400px;
margin: 20px auto;
overflow: scroll;
/* overflow: hidden; */
}
.box {
height: 80px;
margin: 20px auto;
background-color: white;
}

마진 병합 현상을 알고 나서 코드를 수정하여 다음과 같이 처음 의도했던 스타일을 되찾을 수 있었다.

내부의 section 요소들 사이에 마진을 따로 부여하지 않아도 마진이 생긴 것처럼, 마진 병합 현상을 잘 이용한다면 두 block 요소 간 마진을 개별적으로 설정하지 않아도 된다는 장점이 있다. 다만 부모 요소와 자식 요소 사이의 마진 병합 현상도 고려해야 하기에, 겹치는 부분이 없는지 확인할 필요가 있을 것이다.