마진 병합

CSS에서, A 상자의 margin-top과 B 상자의 margin-bottom이 하나의 마진으로 합쳐질 수 있다. 이렇게 합쳐진 마진은 병합된다고 한다.

수직으로 인접한 마진은 병합된다. 단, 다음의 경우는 병합이 일어나지 않는다.

  • 루트 요소 박스의 마진은 병합되지 않는다.

  • If the top and bottom margins of an element with clearance are adjoining, its margins collapse with the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block.

    이 한 문장을 해석하면,

    clearance가 있는, 높이가 0인 A 박스의 마진 탑과 마진 바텀이 인접할 때, A 박스의 형제 요소와의 마진은 병합하지만 A 요소를 포함하는 부모 요소와의 마진 바텀은 병합되지 않는다.

    이 문장의 표현이 굉장히 모호해서 오해를 불러일으키기 쉽다. 처음에 해석할 때 A상자와 B상자의 마진이 인접할때를 말하는 줄 알고 고생을 많이 했다.
    그러던중, stack overflow에서 나와 같은 생각을 하는 글을 봤고 이게 높이가 0인 상자의 마진이 인접한 경우라는 것을 깨달았다.

    stack overflow 해당 페이지 이 글의 작성자에게 매우 감사함을 느꼈다.

    또, 여기서 clearance가 무엇인지 의문을 가질 수 있는데 이 글은 마진 병합에 대한 설명글이기 때문에 다른 페이지에 작성해두었다. 링크를 클릭해 개념을 익히고 오자.

    자, 이제 이에 대한 예시를 살펴보자.

    See the Pen with clearance인 경우 마진 병합 by kimjaemin (@jaime_jam) on CodePen.

clearance가 있는 경우, 부모 블록과 병합되지 않는다.

그렇다면 clearance가 없으면 부모 블록과 병합되는지 안되는지 확인해보자.

See the Pen Clearance가 없는 경우에서 높이값 0인 상자 만들기 by kimjaemin (@jaime_jam) on CodePen.

이럴수가..! 병합된다. 분명 스펙에 따르면 clearance가 있으면 부모 블록과 병합되지 않는다고 했다. 무슨 문제인걸까? 앞에서 해석 문제로 며칠을 고생하고 이번엔 이걸로 며칠을 고생했다. 결론을 말하자면 크롬 문제이다.

파이어폭스, 사파리, 익스플로러에서 확인을 해봤다.

파이어폭스, 사파리, 익스의 결과 화면

모두 병합이 잘 된다. 제일 믿음직스러웠던 크롬이 이런 문제가 있다니.. 다른 브라우저에선 잘 작동하는 걸로 보아 크롬에서 뭔가 문제가 생긴듯하다.
아무리 크롬이여도 늘 의심하고 확인해보는 습관을 가져야겠다고 마음먹었다.
계속해서 마진 병합에 대해 설명해보자.

수평적 마진, 즉 박스가 수평으로 놓일 때는 마진 병합이 절대 일어나지 않는다.

다음과 같은 경우에만 두 상자의 마진이 병합될 수 있다.

  • 둘 다 같은 BFC에 존재하는 블록 상자일 경우

  • 라인 박스, 간격, 패딩 및 경계선이 없을 경우
    두 개의 상자를 구분하는 일종의 경계선이 없어야 한다.

  • 둘 다 수직적으로 인접한 상자의 가장자리에 속해야 한다.

    • 부모 상자의 위쪽 마진과 부모 상자의 첫 번째 자식 상자의 위쪽 마진
    • 두 개의 형제 상자의 위쪽 마진과 아래쪽 마진
    • 부모 상자의 높이값이 auto일 때, 부모 상자의 아래쪽 마진과 마지막 자식 상자의 아래쪽 마진
    • 어떤 상자 A의 min-height 속성값이 0이고, 경계선을 정하는 것들(보더, 패딩, 라인박스)이 없고, height 속성값이 0 혹은 auto이면 A 상자의 자식 마진(자식 요소가 있다면)은 병합된다.

인접 마진은 형제 요소나 부모 요소와 연관이 없더라도 생성될 수 있다.

1. float된 박스와 어떤 상자(any other box)간의 마진은 병합하지 않는다.
(float된 부모 상자와 그 자식 상자간에도 마진 병합은 일어나지 않는다.)

2. 새로운 BFC를 형성하는 박스와 그 자식 상자의 마진은 병합되지 않는다.

예제를 통해 살펴보자.

모든 상자가 normal flow 상태일 경우, 자식 요소인 child 상자에 margin-top 속성을 주면 마진이 병합된다.
그렇다면, parent 상자에 속성을 추가하여 새로운 BFC를 형성하도록 하면 어떻게 될까?

See the Pen WNwELBz by kimjaemin (@jaime_jam) on CodePen.

parent 박스에 overflow:hidden;을 사용해서 새로운 BFC를 형성했다.
그러자, 자식 요소인 child1 박스의 마진이 병합되지 않는 것을 알 수 있다. 그런데, child1과 child2의 마진은 병합된다.
왜 그럴까? 이 둘은 같은 BFC 위에 존재하기 때문에 병합된다.

3. absolutely positioned 상태의 박스의 마진은 겹치지 않는다.(자식박스의 마진과도 겹치지 않는다.)

absolutely position 상태란, position 속성의 값이 absolute 이거나 fixed인 상태를 말한다.
예제를 통해 살펴보자.

parent 박스는 position: fixed 상태로 margin-top 속성을 주어도 병합이 일어나지 않았고 자식 박스에서 margin-top을 주어도 병합없이 그대로 적용되는걸 알 수 있다.

4. inline-block 박스의 마진도 겹치지 않는다. (자식박스의 마진과도 겹치지 않는다.)

5. 블록 상자의 아래쪽 마진과 그 형제 요소의 위쪽 마진은 항상 겹친다. 그런데, 형제 요소가 clearance를 가지면 마진이 겹치지 않는다.

6. 블록 상자의 위쪽 마진과 첫 번째 자식 상자의 위쪽 마진은 겹친다. 단, 그 둘을 구분하는 경계선이 없어야 한다.(보더, 위쪽 패딩, 자식이 clearance가 없는 경우 등)

7. 박스의 마진은 병합된다.(자식의 마진 또한 병합된다.)
언제? min-hieght 속성값이 0일때, 박스의 위쪽 아래쪽 보더나 패딩도 없을때, height 속성값이 0이나 auto 일때, 그리고 line box를 가지고 있지 않을때

두 개 혹은 그 이상의 마진이 병합될때, 마진의 크기는 겹쳐지는 마진 값 중 가장 큰 값으로 결정된다. 음수 마진의 경우, 음수값을 가지는 마진의 절대값을 양수 마진값에서 뺀 값으로 결정된다. 만약, 둘 다 음수 값을 가지는 마진이라면 0에서 절대값이 가장 큰 마진을 뺀 값으로 결정된다.

상자의 위쪽 및 아래쪽 여백이 인접하면 여백이 축소 될 수 있습니다.그것. 이 경우 요소의 위치는 여백이 축소되는 다른 요소와의 관계에 따라 달라집니다.

요소의 여백이 부모의 위쪽 여백과 함께 축소되면 상자의 위쪽 테두리 가장자리가 부모의 가장자리와 동일하게 정의됩니다.
그렇지 않으면 요소의 부모가 여백 축소에 참여하지 않거나 부모의 아래쪽 여백 만 포함됩니다. 요소의 위쪽 테두리 가장자리의 위치는 요소의 아래쪽 테두리가 0이 아닌 경우와 동일합니다.
축소 된 요소의 위치는 여백이 축소되는 다른 요소의 위치에 영향을주지 않습니다. 위쪽 테두리 가장자리 위치는 이러한 요소의 하위 항목을 배치하는 데만 필요합니다.