[css] 여백 상쇄 or 마진 상쇄(margin collapsing)

·2022년 12월 9일
0

개발 기록

목록 보기
42/68

마진 상쇄

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

이미지 출처

이미지를 보면 요소 A의 margin-bottom: 10px 이고 요소 B의 margin-top: 30px이다. 요소 B의 마진이 요소 A의 마진보다 값이 크다.

이렇게 위아래로 겹쳐진 요소 간의 top과 bottom의 마진이 모두 존재할 때 더 큰 값만 적용되고 작은 값은 무시된다. 이 현상을 상쇄된다고 표현한다.

그래서 결과물은 이미지의 화살표 오른쪽처럼 30px만 적용되는 것이다.

만약 50px, 20px가 아니라 30px, 30px라면 하나만 렌더링 된다.
좌우 여백은 해당되지 않는다.

마진 상쇄 규칙

  • 인접한 block-level 요소들 사이에서 발생한다.
  • 마진 값이 0이더라도 적용된다.
  • 좌우 마진은 마진 상쇄가 발생하지 않는다.

마진 상쇄가 발생하지 않는 예외 케이스

  • 박스가 position: absolute 일 때
  • 박스가 float: left/right 일 때 (clear 되지 않아야 함)
  • flex 컨테이너와 flex 아이템 일 때
  • grid 컨테이너와 grid 아이템 일 때

상쇄되다 !== 없어진다

출처: 네이버 국어사전

국어사전을 보면 상쇄된다는 말은 효과가 없어지는 것을 말한다.
마진의 효과는 화면에 렌더링 되는 것이니까 상쇄된 더 작은 마진은 화면에 나타나지 않는다. 하지만 지정된 값 자체가 없어지는 것은 아니다.

<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;
}

W3Schools 예제

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

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

그런데 파란색 요소를 확인하면 margin-top 영역이 존재한다. 여백이 상쇄된 것이지 없어진 것이 아니다.

마진 상쇄가 일어나는 3가지 상황

인접 형제 박스 간 상하 마진이 겹칠 때

위에서 예시로 든 상황이 바로 이 상황이다.

빈 요소의 상하 마진이 겹칠 때

빈 요소

  • 높이(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>

예제를 만들어봤다.

  • 초록색(parent) margin: 30px 0
  • 빨간색 margin-top: 20px
  • 파란색 margin-bottom: 20px

개발자 도구로 확인해 보면,

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

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

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

이 경우 자식 요소의 마진 값이 살아남더라도 부모 요소에 마진이 적용된 것처럼 보이게 된다.

마진이란 콘텐츠 간의 간격이고, 간격을 벌리기 위해서는 경계를 필요로 합니다. 브라우저는 부모 박스와 첫 번째(마지막) 자식 박스 간의 경계를 그 사이에 있는 border / padding / inline 콘텐츠 유무로 판단합니다. 앞에 설명했던 빈 박스의 마진 상쇄 현상과는 조금 다르게, 이미 명시적으로 height / min-height 값을 줬더라도 이번 경우에선 신경 쓰지 않습니다. [CSS 마진 상쇄(Margin-collapsing) 원리 완벽 이해]

정리

케이스를 나눠보니 경계를 인식할 수 있냐가 마진 상쇄가 발생하는 기준인 것 같다.
경계를 만들어 주는 것이 해결법이라고 하는데 padding을 주거나, border를 주거나, 사이에 인라인 요소를 삽입하거나 하는 해결법이 존재한다.

참고자료

0개의 댓글