마진 병합 현상(Margin Collapsing)

ursr_log·2020년 7월 19일
20

CSS

목록 보기
1/10
post-thumbnail

YouTube 빔캠프 VEAMCAMP채널_ 코딩가나다 시리즈의 margin collapsing 강좌를 보며 정리한 글입니다.

마진 병합 현상과 해결법

마진(margin)이란 요소의 네 방향 바깥 여백 영역을 설정하는 css속성이다.
여러 요소에 마진값이 넣어져 있을 때 의도치않게 요소의 여백이 줄어들어져있거나 여백을 늘려도 늘어나지 않는 현상들을 겪을 수 있다.
마진이 병합되는 현상에 대한 내용을 정리해보았다.

마진 병합 현상(Margin Collapsing)

마진 병합 현상은 인접하는 블록요소의 상하단의 마진이 병합되는 현상을 말한다.
마진의 크기는 병합되는 마진 중에서 큰 값을 가진 마진의 값으로 병합된다.

마진병합현상의 조건

  • 인접하는 Block요소끼리만 일어난다.
  • 상하단만 병합현상이 일어난다(좌우의 여백의 병합은 일어나지 않음).

블록요소의 상하단 마진의 병합

인접하는 두 블록요소에 각각 margin:20px;의 속성을 줬을 때,
위의 그림을 보면 section1의 하단 마진부분과 section2의 상단 마진부분이 서로 겹쳐져서
그 사이의 마진이 총 40px이 아닌 20px이 되는 것을 볼 수 있다.
이렇게 마진병합현상은 의도된 현상이여서 디자인을 안정적으로 하는데 도움이 된다.

부모 자식 요소간의 마진 병합

그런데 부모와 자식 요소간의 마진도 겹침 현상이 일어난다.

이렇게 부모요소와 자식요소가 있을 때 먼저, 부모요소에는 margin값을 위아래 0 좌우 auto를 주고 자식요소에는 margin을 주지 않은 모습이다.

그러다가 자식요소인 child에 margin값을 각각 50px씩 주면 어떻게 될까.
부모와 자식요소간의 마진 병합현상이 없다고 생각하면 주황색 자식요소에 위 아래 좌 우 모두 50px씩 마진이 생겨서 parent의 흰색 background가 마치 숫자8처럼 보이게 될 것이라 예상할 수 있다.
그러나 결과는 child의 위 아래 margin값이 들어가지 않아보이는 H모양의 결과가 나오게 된다.

숫자 8모양의 결과를 예상했던사람에게는 의도되지 않은 결과가 될 수 있다.
child의 위 아래의 마진은 어디로 간걸까?
바로, 부모요소의 마진으로 병합되어 마치 .parent요소의 마진처럼 표현 된 것이다.

위의 그림을 보면 부모요소의 마진으로 50px이 들어간 것을 알 수 있다.
자식요소와 부모요소의 마진이 병합된 것인데, 앞서 살펴본 마진병합현상의 조건에 인접하는 블록요소의 상하단은 마진 병합이 일어난다고 했다.
위의 예시는 부모자식요소 모두 div인 블록요소로 만들었다.
때문에 상단의 마진과 하단의 마진이 병합된 결과가 나타난 것이다.
그렇다면 내가 원하던 8자 모양이 되도록(child의 위아래 50px의 마진이 표시되게 하려면) 어떻게 해야할까?

마진 병합현상 일어나지 않게 하기

1-1. 공간을 차지하고있는 요소를 해당 자리에 넣는다.

<div class="parent">
    나는 짱
    <div class="child">A</div>
  	나는 내가 짱
    <div class="child">B</div>
    내가 짱
</div>

위 코드와 같이 parent와 A child요소 사이에 '나는 짱'이라는 텍스트를,
B child요소와 parent의 닫힘태그 사이에 '내가 짱'이라는 텍스트를,
그리고 A child와 B child사이의 마진병합또한 없애보기위해 둘 사이에 '나는 내가 짱'이라는 텍스트를 넣어보았다.

마진병합현상으로 표시되지 않았던 위아래 마진이 보이고 A child와 B child사이의 마진병합현상도 없어졌다.
이렇게 공간을 차지하고있는 텍스트같은 요소가 마진 병합현상이 일어나는 자리에 있으면 마진 병합현상은 일어나지 않는다.
부모와 자식이 온전히 떨어지기 때문이다.
그러나 디자인상 이렇게 텍스트를 보이게 할 수는 없으니 text를 넣는것 대신 parent요소에 border속성을 준다거나 padding속성을 주는 것으로도 마진병합 현상을 없앨 수 있다.

padding: 1px;
/* 또는 */
border: 1px solid transparent;

padding속성값을 1px주거나 또는 border를 투명한 선으로 1px 주게되면 마진 병합 현상을 없앨 수 있다.

그러나 이렇게 되면 어쨌든 1px의 공간을 차지하는 것이기 때문에 의도한 디자인에서 1px의 오차가 발생하게되어 마진병합현상을 온전히 해결하는 해결책이라고는 볼 수 없다.
그렇다면 오차가 발생하지 않게 하면서 마진병합현상을 없애는 방법에는 무엇이 있을까?

1-2. 빈 table태그를 넣는다.

<div class="parent">
    <table></table>
    <div class="child">A</div>
    <div class="child">B</div>
    <table></table>
</div>

선생님께서 추가적으로 알려주신 꿀팁이다.
이렇게 부모와 자식요소 사이에 비어있는 table태그를 넣어주면 마진겹침 현상을 없앨 수 있다.
"table태그 자체는 아무런 크기가 없응께 티가 안나고 좋습니다!"
선생님 목소리가 귀에 들리는 것 같다.
하지만 마크업이 복잡해지는데 이는 css로 가상요소를 활용하여 처리 할 수 있다.

.parent::before,
.parent::after {
   content: "";
   display: table;
}

2.자식요소의 display속성값을 inline-block으로 바꾸기

.child {
   display: inline-block;
}

마진병합현상의 조건으로는 인접하는 블록요소의 상하단은 마진이 병합되는 것이기 때문에 자식요소의 display속성값을 inline-block으로 바꿔주는것으로 간단히 해결이 된다.

이렇게 자식요소의 속성값을 inline-block으로 바꿔주고나니 상단과 하단의 마진병합현상은 물론 A child요소와 B child요소 사이의 마진 병합현상까지도 제거되었다.
그.런.데...이때!!(서프라이즈 톤)
그럼 만약 형제간의 마진병합은 냅두고 상하단의 부모자식간의 마진병합현상만 제거하고 싶다면 어떻게 해야할까?(그렇게 하는게 보기에 더 좋으니까)
물론 제일 상단의 자식요소를 뺀 나머지 자식요소들의 margin-top값을 0으로 조절하면 되겠지만 그런 번거로운 방법 말고 다른 방법을 찾아보자.

3. overflow:hidden; 속성을 이용하여 해결하기

.parent {
	overflow: hidden;
}

부모요소의 속성값으로 overflow:hidden;을 주면 말끔히 해결된다.
부모요소에게 overflow:hidden;속성값을 적용하면 새로운 block format context가 .parent요소 기준에서 만들어지면서 .parent의 마진과 .child의 마진은 별개가 되고, 안에 있는 child요소의 마진이 부모요소의 안에서 새로 시작할 수 있는 것이다.
때문에 새로운 block format context에있는 자식요소인 child A요소의 위 여백과 child B요소의아래 여백이 표현되며 child A요소와 child B요소 사이의 마진은 그대로 병합된다.

참고영상
생활코딩-마진겹침
마진병합 margin collapsing | 코딩가나다 | 빔캠프

2개의 댓글

comment-user-thumbnail
2020년 7월 21일

오늘도 잘보고 갑니다.

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

잘봤습니다. 이슈 해결에 도움이 되옸습니다 감사합니다.

답글 달기