안녕하세요! 프론트엔드 개발의 세계로 나아가기 위해 오늘도 열심히 달리고 계시군요. 포트폴리오로 준비 중이신 독후감 사이트나 웹 프로필 페이지를 만들다 보면, 요소들 사이의 간격을 조절하기 위해 margin을 정말 많이 사용하게 되실 텐데요.
"어? 왜 내가 준 마진만큼 안 떨어지고 딱 붙지?" 혹은 "왜 자식 요소에 마진을 줬는데 부모 요소가 통째로 밑으로 밀려나지?"라며 당황하신 적 없으신가요? 프론트엔드 개발자라면 누구나 한 번쯤 겪는 이 기이한 현상, 버그가 아니라 CSS의 의도된 기능이랍니다. 바로 오늘 우리가 살펴볼 '마진 병합(Margin collapsing)'이죠.
실무에서 레이아웃이 와장창 깨지는 원인 1순위이기도 한 이 개념, 저와 함께 공식 문서를 통해 완벽하게 마스터해 봅시다!
블록(block) 요소들의 상단(top)과 하단(bottom) 마진은 가끔 결합하여(병합되어) 단일 마진 하나로 합쳐지기도 합니다. 이때 합쳐진 마진의 크기는 개별 마진들 중 가장 큰 값(만약 두 마진의 크기가 같다면 그중 하나의 값)이 되는데요, 이러한 동작 방식을 마진 병합(margin collapsing)이라고 부릅니다.
단, 부동(floating) 요소와 절대 위치(absolutely positioned)가 지정된 요소의 마진은 절대 병합되지 않는다는 점을 유의하세요.
💡 강사 팁:
"도대체 왜 이런 귀찮은 기능을 만든 거야?"라고 생각하실 수 있습니다. 사실 CSS가 처음 만들어질 당시에는 웹 문서가 지금처럼 화려한 앱 UI가 아니라 '글(문서)' 위주였거든요. 독후감 사이트의 본문처럼 여러 개의 문단(<p>)이 나열될 때, 문단 위아래로 일정한 여백을 유지하기 위해 고안된 '타이포그래피' 친화적인 기능이랍니다.
마진 병합은 크게 세 가지 기본 상황에서 발생합니다:
인접한 형제 요소 (Adjacent siblings) 인접해 있는 형제 요소들의 마진은 서로 병합됩니다. (단, 뒤에 오는 형제 요소가 `float`된 요소들을 지나쳐서 clear 되어야 하는 경우는 제외합니다.)부모와 자손을 분리하는 콘텐츠가 없는 경우 (No content separating parent and descendants) 부모 블록과 그 자손 요소 사이의 수직 마진도 병합될 수 있습니다. 이 현상은 부모와 자식 사이에 둘을 시각적으로 분리할 만한 콘텐츠가 없을 때 발생합니다. 구체적으로는 다음 두 가지 주요 상황에서 일어납니다:👨🏫 부연 설명:
위에 있는 박스에margin-bottom: 30px을 주고, 바로 아래 있는 박스에margin-top: 20px을 주면 두 박스 사이의 간격은 50px이 될 것 같지만, 실제로는 더 큰 값인 30px만 적용되어버립니다. 서로 겹쳐버리는 거죠!
margin-top은 자신의 첫 번째 일반 흐름(in-flow) 자손의 margin-top과 병합됩니다. 단, 부모 요소에 border-top이나 padding-top이 있거나, 인라인 콘텐츠(텍스트 등)가 포함되어 있거나, clearance(클리어 여백)가 적용된 경우는 예외입니다.margin-bottom은 자신의 마지막 일반 흐름(in-flow) 자손의 margin-bottom과 병합됩니다. 단, 부모 요소에 height나 min-height가 정의되어 있거나, border-bottom, 또는 padding-bottom이 있는 경우는 예외입니다.두 경우 모두, 부모 요소에 새로운 블록 서식 문맥(block formatting context, BFC)을 생성해 주면 부모와 자식 간의 마진 병합을 방지할 수 있습니다.
빈 블록 (Empty blocks) 어떤 블록의💡 강사 팁:
"자식한테 마진을 줬는데 부모가 같이 밑으로 내려가요!"라는 질문이 실무에서 쏟아집니다. 자식의 마진이 부모 밖으로 '새어 나가서' 부모의 마진과 합쳐지기 때문이죠. 이걸 막으려면 부모에게overflow: hidden을 주거나(새로운 BFC 생성), 부모에padding을 1px이라도 주면 깔끔하게 해결됩니다!
margin-top과 margin-bottom을 분리해 줄 테두리(border), 패딩(padding), 인라인 콘텐츠, height, 또는 min-height가 전혀 없다면, 그 빈 블록의 상단 마진과 하단 마진은 서로 병합되어 버립니다.
추가로 알아두어야 할 몇 가지 사항들:
display 속성이 flex나 grid로 설정되어 있다면 그 안에서는 마진 병합이 일어나지 않습니다.👨🏫 부연 설명:
바로 마지막 줄이 핵심입니다. Next.js나 React 환경에서 컴포넌트를 배치할 때display: flex와gap속성을 애용하시면, 이런 골치 아픈 마진 병합을 피해 훨씬 예측 가능하고 견고한 레이아웃을 만드실 수 있습니다!
<p>The bottom margin of this paragraph is collapsed …</p>
<p>
… with the top margin of this paragraph, yielding a margin of
<code>1.2rem</code> in between.
</p>
<div>
This parent element contains two paragraphs!
<p>
This paragraph has a <code>.4rem</code> margin between it and the text
above.
</p>
<p>
My bottom margin collapses with my parent, yielding a bottom margin of
<code>2rem</code>.
</p>
</div>
<p>I am <code>2rem</code> below the element above.</p>
div {
margin: 2rem 0;
background: lavender;
}
p {
margin: 0.4rem 0 1.2rem 0;
background: yellow;
}
아래의 라이브 결과 화면을 확인해 보세요:
MDN Playground에서 실행해보기 (Live Sample)
<p> 태그를 보면, 위의 <p>는 하단 마진 1.2rem, 아래의 <p>는 상단 마진 0.4rem을 가집니다. 둘 중 더 큰 값인 1.2rem으로 병합되어 두 단락 사이의 간격이 결정됩니다.<div>는 2rem 0의 마진을 가지고, 그 안의 마지막 <p> 태그는 하단 마진 1.2rem을 가집니다. 부모와 마지막 자식 사이에 패딩이나 보더가 없기 때문에 자식의 하단 마진이 밖으로 빠져나와 부모의 하단 마진 2rem과 병합됩니다. 결국 더 큰 값인 2rem의 간격이 제일 마지막 <p> 태그와의 사이에 적용됩니다.이 페이지가 도움이 되셨나요?
[Yes][No]
기여하는 방법 알아보기(Learn how to contribute)
이 페이지의 마지막 수정일은 2025년 11월 20일이며, MDN 기여자들에 의해 수정되었습니다.
어떠신가요? 처음에는 왜 이러나 싶던 레이아웃의 반항(?)도 원리를 알고 나니 꽤 합리적으로 느껴지지 않나요?
오늘 배우신 마진 병합의 규칙을 기억해 두신다면, 앞으로 포트폴리오의 레이아웃을 짤 때 불필요한 마진의 중복을 막고, BFC나 Flexbox를 적재적소에 활용하여 완벽한 UI를 구현하실 수 있을 겁니다. 또 다른 궁금한 점이 생기면 언제든지 질문 남겨주세요!