[CSS] 마진 병합 현상 (margin collapsing)

진욱·2023년 12월 10일

CSS

목록 보기
3/3


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

이 당시 나의 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;
}

MDN을 통해 확인한 마진 병합 현상에 대한 정의는 다음과 같다.

여러 블록의 위쪽 및 아래쪽 마진은 경우에 따라 제일 큰 마진의 크기를 가진 단일 마진으로 결합(상쇄)되곤 합니다. 이런 동작을 마진 상쇄라고 부릅니다.


마진 병합 현상의 조건

마진 병합 현상이 일어날 수 있는 조건은 두 가지로, 다음과 같다.

  1. Block-level element 여야 한다.
  2. 인접하는 요소의 상하단 마진만 병합된다. 좌우 마진은 겹치더라도 상쇄되지 않는다.
  • 마진 병합 현상이 발생하더라도 최상위 (root) 요소인 html 요소는 적용을 받지 않는다.

마진 병합 현상이 발생하는 경우

마진 병합 현상은 다음과 같은 세 가지 경우에 발생한다.

1. 인접하는 형제 간 상하 마진이 겹치는 경우

인접 형제 요소간의 상하 마진은 병합되는데, 겹쳐진 두 마진 값을 비교해, 더 큰 마진 값으로 병합된다.

2. 빈 블록인 경우

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

3. 부모와 자손을 분리하는 콘텐츠가 없을 때

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


마진 병합 현상 해결 방법

1. block 요소를 inline-block 요소로 변경한다.

마진 병합 현상은 block 요소일 때만 발생한다는 조건에 위배되므로, block 요소의 display property를 inline-block 으로 변경한다면 마진 병합 현상을 해결할 수는 있다. 다만 inline 속성에 의해 baseline 기준으로 정렬되어 이를 해결해야 한다는 번거로움이 있을 것 같다.

2. "부모 요소"에 border 값을 부여한다.

부모 요소에 border 값을 설정하면, border 가 영역을 차지하므로 경계가 생기고, 이 경계를 기준으로 마진 값이 나뉘게 되어 마진 병합 현상을 해결할 수 있다. 하지만 border 역시 영역을 차지하게 되기 때문에, 의도한대로 스타일링을 하는데 번거로움이 있을 수 있다고 생각한다.

.wrapper {
  width: 400px;
  margin: 20px auto;
  border: 1px solid red;
}

.box {
  height: 80px;
  margin: 20px auto;
  background-color: white;
}



3. "부모 요소"에 padding 값을 부여한다.

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

.wrapper {
  width: 400px;
  margin: 20px auto;
  padding: 20px 0;
}

.box {
  height: 80px;
  margin: 20px auto;
  background-color: white;
}



4. 부모 요소의 display 속성을 flow-root 로 지정한다.

최상위 (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;
}



5. 부모 요소에 height를 지정한 후, overflow 값을 부여한다.

부모 요소에 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 요소 간 마진을 개별적으로 설정하지 않아도 된다는 장점이 있다. 다만 부모 요소와 자식 요소 사이의 마진 병합 현상도 고려해야 하기에, 겹치는 부분이 없는지 확인할 필요가 있을 것이다.

0개의 댓글