부모에 준 여백이 사라지고 자식의 margin이 밖으로 삐져나온 이유
문제 발생
카드 안쪽 여백을 자식 제목의 margin-top으로 줬는데, 그 여백이 카드 바깥으로 나갔습니다.
<section class="card">
<h2>제목</h2>
</section>.card { background: #fff; }
h2 { margin-top: 24px; } /* 카드 위쪽 바깥에 24px이 생김 */형제 요소 사이에서도 margin-bottom: 16px과 margin-top: 24px을 줬는데 합이 40px이 아니라 24px이었습니다.
원인 분석
마진 상쇄(margin collapsing)입니다. MDN은 상쇄가 일어나는 경우를 셋으로 정리합니다.
인접 형제 — 인접한 형제의 마진은 개별 마진 중 가장 큰 값 하나로 병합됩니다. 16px과 24px이 40px이 아니라 24px이 된 이유입니다.
부모와 자손 — 사이를 막는 내용이 없으면 부모의 margin-top이 첫 in-flow 자식의 margin-top과 병합됩니다. MDN은 예외도 함께 적습니다 — 부모에 border-top, padding-top, (텍스트 같은) 인라인 내용, clearance가 있으면 병합되지 않습니다. margin-bottom 쪽은 부모에 **height/min-height, border-bottom, padding-bottom**이 있으면 막힙니다.
빈 블록 — 위아래 마진 사이를 가로막는 것이 아무것도 없으면 자기 자신의 두 마진이 서로 병합됩니다.
그리고 결정적으로, MDN이 명시하듯 마진 상쇄는 세로 방향에서만 일어납니다.
해결 방안
- 여백은 컨테이너의
padding으로 줍니다. 안쪽 여백을 자식 마진으로 표현하는 것 자체가 이 문제의 출발점입니다.
.card { padding: 24px; }
h2 { margin-top: 0; }- 레이아웃 컨테이너를 flex/grid로 만듭니다. MDN이 나열하는 비상쇄 조건 중 하나입니다 —
display: flex나display: grid컨테이너 안에서는 마진이 상쇄되지 않습니다.gap을 쓰면 형제 간 간격 계산도 예측 가능해집니다.
.card { display: flex; flex-direction: column; gap: 16px; }-
새 블록 서식 문맥(BFC)을 만드는 것도 방법입니다.
overflow: auto등이 상쇄를 끊습니다. 다만 스크롤 동작이 함께 바뀌므로 부작용을 감수할 때만 씁니다. -
음수 마진이 섞이면 규칙이 또 다릅니다. MDN 설명대로 부호가 섞이면 가장 큰 양수 마진과 가장 작은(가장 음수인) 마진의 합이고, 전부 음수면 그중 가장 작은 값입니다. 계산을 머리로 하지 말고 실제로 확인합니다.
-
띄어쓰기 방향을 하나로 정합니다. "모든 요소는
margin-bottom만 준다" 같은 팀 규칙 하나가 이 종류의 디버깅을 대부분 없앱니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.