Display/Block formatting context

김동현·2026년 3월 21일

mdn 학습 번역 - CSS

목록 보기
85/190

안녕하세요! 오늘 다뤄볼 주제는 CSS 레이아웃의 가장 중요한 원리 중 하나인 블록 서식 문맥(Block Formatting Context, 줄여서 BFC)입니다.

"BFC가 무엇인가요? BFC를 생성하는 방법에는 어떤 것들이 있나요?"라는 질문은 프론트엔드 개발자 면접에서 단골로 등장하는 심화 질문입니다. 레이아웃이 붕괴되거나 마진(margin)이 겹치는 현상 등 CSS를 다루다 보면 마주치는 수많은 '이유를 알 수 없는 현상'들의 비밀이 바로 이 BFC에 숨어 있거든요.

이 문서를 꼼꼼히 번역하면서 실무에 바로 적용할 수 있는 팁들도 짚어드리겠습니다. 준비되셨나요?


블록 서식 문맥 (Block formatting context)

블록 서식 문맥(Block formatting context, BFC)은 웹 페이지의 시각적 CSS 렌더링의 일부분입니다. BFC는 블록 상자(block boxes)들의 레이아웃이 이루어지는 영역이자, 플로트(floats, 떠 있는 요소들)가 다른 요소들과 상호작용하는 구역을 말합니다.

블록 서식 문맥은 다음 조건 중 적어도 하나를 충족할 때 생성됩니다:

  • 문서의 루트(최상위) 요소 (<html>).
  • 플로트 (요소의 float 속성값이 none이 아닌 요소).
  • 절대 위치가 지정된 요소 (요소의 position 속성값이 absolute 또는 fixed인 요소).
  • 인라인 블록 (요소의 display 속성값이 inline-block인 요소). 이는 <button>과 버튼 역할의 <input> 요소들의 기본 디스플레이 타입이기도 합니다.
  • 표의 셀 (요소의 display 속성값이 table-cell인 요소. HTML 표(table) 셀의 기본값).
  • 표의 캡션 (요소의 display 속성값이 table-caption인 요소. HTML 표 캡션의 기본값).
  • display: table, table-row, table-row-group, table-header-group, table-footer-group (각각 HTML의 표, 행, 본문, 헤더, 푸터의 기본값) 또는 inline-table을 가진 요소에 의해 암시적으로 생성된 익명(anonymous)의 표 셀.
  • 요소의 display 속성값이 flow-root인 요소.
  • 플렉스 아이템 (요소의 displayflex 또는 inline-flex인 요소의 직계 자식). 단, 자식 요소 자체가 또 다른 플렉스(flex), 그리드(grid), 또는 표(table) 컨테이너가 아닐 경우에 해당합니다.
  • 그리드 아이템 (요소의 displaygrid 또는 inline-grid인 요소의 직계 자식). 단, 자식 요소 자체가 또 다른 플렉스, 그리드, 표 컨테이너가 아닐 경우에 해당합니다.
  • 블록 요소의 overflow 속성값이 visible이나 clip이 아닌 요소 (예: auto, hidden, scroll).
  • 요소의 contain 속성값이 layout, content, 또는 paint인 요소.
  • 다단(Multicol) 컨테이너 (요소의 column-countcolumn-width 속성값이 auto가 아닌 요소. column-count: 1인 요소 포함).
  • 요소의 column-span 속성값이 all인 요소. (해당 요소가 다단 컨테이너 안에 있지 않더라도 BFC를 생성합니다.)

새로운 블록 서식 문맥(BFC)을 형성하는 요소는 레이아웃에 지대한 영향을 미치는데, 그 이유는 다음과 같은 세 가지 동작을 수행하기 때문입니다:

  1. 내부에 있는 플로트(floats) 요소들을 감쌉니다(contain).
  2. 외부에 있는 플로트 요소들과 영역이 겹치지 않고 밀어냅니다(exclude).
  3. 마진 상쇄(margin collapsing) 현상을 막아줍니다(suppress).

💡 강사의 기술 면접 대비 팁!
면접관: "BFC(Block Formatting Context)가 무엇인지, 그리고 어떤 역할을 하는지 설명해 주세요."
모범 답안: "BFC는 CSS가 블록 레벨 요소들을 배치하고 플로트(float) 요소들과 상호작용하는 독립적인 렌더링 구역입니다. BFC를 생성하는 대표적인 방법으로는 overflow: hidden, display: flex, 그리고 모던 CSS인 display: flow-root 등이 있습니다. BFC가 생성되면 1) 내부의 float 요소가 부모 박스 밖으로 삐져나가는 현상(Clearfix 이슈)을 해결해주고, 2) 부모와 자식 간에 발생하는 불필요한 마진 병합(Margin Collapsing) 현상을 막아준다는 중요한 특징이 있습니다."

플렉스(flex) 컨테이너나 그리드(grid) 컨테이너(요소의 displayflex, grid, inline-flex, inline-grid로 설정하여 정의됨)는 새로운 플렉스 또는 그리드 서식 문맥을 설정합니다. 이것들은 블록 서식 문맥(BFC)과 비슷하지만, 플렉스나 그리드 컨테이너 내부에서는 자식 요소들이 플로트(floating)될 수 없다는 점이 다릅니다. 하지만 이 서식 문맥들도 외부의 플로트 요소를 배제(exclude)하고 마진 상쇄를 막아주는(suppress) 역할은 동일하게 수행합니다.

이 문서에서 다룰 내용 (In this article)


예제 (Examples)

새로운 BFC를 생성했을 때 어떤 효과가 나타나는지 몇 가지 예제를 통해 확인해 보겠습니다.

내부 플로트 감싸기 (Contain internal floats)

다음 예제에는 플로트된(floated) 콘텐츠와 그 옆에 나란히 놓인 일반 콘텐츠가 있습니다. 테두리(border)가 있는 <div> 안에 플로트된 요소가 들어있습니다. <div> 안의 일반 콘텐츠는 플로트 요소 옆으로 흘러갑니다. 그런데 플로트 요소의 높이가 일반 콘텐츠의 높이보다 길기 때문에, 플로트 요소가 <div>의 아래쪽 테두리를 뚫고 삐져나온 것을 볼 수 있습니다. 흐름 내부 및 외부 요소(in flow and out of flow elements) 가이드에서 설명했듯이, 플로트 요소는 정상적인 흐름(normal flow)에서 벗어나기 때문에 <div>backgroundborder는 일반 콘텐츠만 감쌀 뿐 플로트 요소는 감싸지 못합니다.

overflow: auto 사용하기

overflow: auto를 설정하거나, 기본값인 overflow: visible이 아닌 다른 값을 설정하면 플로트 요소를 감싸는 새로운 BFC가 생성됩니다. 이제 우리의 <div>는 전체 레이아웃 안에 존재하는 '작은 미니 레이아웃(mini-layout)'이 됩니다. 내부에 있는 모든 자식 요소들은 철저하게 이 미니 레이아웃 안에 갇히게(contained) 됩니다.

overflow 속성을 사용하여 BFC를 생성하는 것의 문제점은, overflow 속성의 원래 목적이 '넘치는 콘텐츠를 어떻게 처리할 것인지 브라우저에게 지시하는 것'이라는 데 있습니다. BFC를 만들겠다는 순수한 목적만으로 이 속성을 남용하다 보면, 원치 않는 스크롤바가 생기거나 그림자 효과(shadows)가 잘려버리는 현상을 겪게 될 수도 있습니다. 또한 코드를 읽는 동료 개발자 입장에서는 왜 여기에 overflow를 썼는지 그 의도를 파악하기 어려울 수 있습니다. 만약 이 용도로 overflow를 쓴다면, 왜 썼는지 주석을 달아두는 것이 좋습니다.

display: flow-root 사용하기

display: flow-root 값을 사용하면 위와 같은 잠재적인 부작용 없이 아주 안전하게 새로운 BFC를 생성할 수 있습니다. 컨테이닝 블록에 display: flow-root를 설정하면 새로운 BFC가 만들어집니다.

<div>display: flow-root;를 적용하면, 그 컨테이너 안에 있는 모든 것들이 해당 컨테이너의 블록 서식 문맥(BFC)에 참여하게 되며, 플로트 요소들은 더 이상 요소의 바닥을 뚫고 삐져나오지 못하게 됩니다.

flow-root라는 이름은, 이 속성이 내부에 있는 플로우 레이아웃에 대해 새로운 문맥을 형성하는 방식이 마치 문서의 root 요소(브라우저의 <html> 요소)처럼 행동하는 무언가를 만들어낸다는 의미에서 붙여진 이름입니다. 이해가 되시나요?

HTML

<section>
  <div class="box1">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the container.</p>
  </div>
</section>
<section>
  <div class="box2">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the <code>overflow:auto</code> container.</p>
  </div>
</section>
<section>
  <div class="box3">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the <code>display:flow-root</code> container.</p>
  </div>
</section>

CSS

section {
  height: 150px;
}
.box1 {
  background-color: rgb(224 206 247);
  border: 5px solid rebeccapurple;
}
.box2,
.box3 {
  background-color: aliceblue;
  border: 5px solid steelblue;
}
.box2 {
  overflow: auto; /* 부작용이 있을 수 있는 구형 방식 */
}
.box3 {
  display: flow-root; /* 깔끔하고 안전한 최신 방식 */
}
.float {
  float: left;
  width: 200px;
  height: 100px;
  background-color: rgb(255 255 255 / 50%);
  border: 1px solid black;
  padding: 10px;
}

첫 번째 박스(보라색)는 BFC가 형성되지 않아 자식 플로트 요소가 박스 밖으로 삐져나왔습니다. 반면 두 번째 박스(overflow: auto)와 세 번째 박스(display: flow-root)는 BFC가 형성되어 부모 박스가 자식 플로트 요소를 완벽하게 감싸고 늘어난 것을 확인할 수 있습니다.


외부 플로트 밀어내기 (Exclude external floats)

다음 예제에서는 display: flow-root와 플로트를 사용하여 두 개의 상자를 나란히 배치했습니다. 이를 통해 정상 흐름(normal flow)에 있는 요소가 새로운 BFC를 설정하면, 자신과 동일한 BFC에 속해 있는 다른 플로트 요소의 마진 박스(margin box)와 영역이 겹치지 않고 밀어낸다는 사실을 증명할 수 있습니다.

HTML

<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box2">
    <p><code>display:flow-root</code></p>
  </div>
</section>

CSS

section {
  height: 150px;
}
.box {
  background-color: rgb(224 206 247);
  border: 5px solid rebeccapurple;
}
.box2 {
  background-color: aliceblue;
  border: 5px solid steelblue;
  display: flow-root; /* BFC 형성! */
}
.float {
  float: left;
  overflow: hidden; /* resize:both 를 사용하기 위해 필요합니다 */
  resize: both;
  margin-right: 25px;
  width: 200px;
  height: 100px;
  background-color: rgb(255 255 255 / 75%);
  border: 1px solid black;
  padding: 10px;
}

첫 번째 Normal 박스(보라색)는 BFC가 형성되지 않았습니다. 따라서 부모 영역 전체를 가로로 다 차지하면서, 플로트 요소의 텍스트 부분만 간신히 피해 가고 박스의 배경과 테두리는 플로트 요소 뒤쪽으로 파고들어가 겹칩니다.
반면 두 번째 flow-root 박스(파란색)는 BFC를 형성했습니다. 이 박스는 플로트 요소(왼쪽)가 차지한 공간을 '자신의 공간'에서 완전히 제외하고, 남은 오른쪽 공간만을 정직하게 차지합니다. 이것이 바로 '외부 플로트를 밀어낸다(exclude external floats)'는 의미입니다. (결과 화면에서 플로트 요소의 크기를 이리저리 드래그해서 줄이거나 늘려보세요!)


마진 상쇄 방지 (Prevent margin collapsing)

인접한 두 요소 사이에서 발생하는 마진 상쇄(margin collapsing) 현상을 피하기 위해서 새로운 BFC를 생성할 수도 있습니다.

마진 상쇄 예제 (Margin collapsing example)

이 예제에는 두 개의 인접한 <div> 요소가 있으며, 각각 상하 마진(vertical margin)으로 10px을 가지고 있습니다. 일반적인 마진 상쇄 현상 때문에 두 요소 사이의 세로 간격은 우리가 예상하는 20px(10 + 10)이 아니라, 상쇄된 10px이 됩니다.

<div class="blue"></div>
<div class="red"></div>
.blue,
.red {
  height: 50px;
  margin: 10px 0;
}

.blue {
  background: blue;
}

.red {
  background: red;
}

마진 상쇄 방지하기 (Preventing margin collapsing)

이 예제에서는 두 번째 <div>를 바깥쪽 <div>로 감싸고(wrap), 그 바깥쪽 <div>overflow: hidden을 적용하여 새로운 BFC를 만들었습니다. 이렇게 새롭게 형성된 BFC는, 내부의 중첩된 <div>가 가진 마진이 바깥쪽을 뚫고 나가서 다른 요소의 마진과 상쇄되는 현상을 막아줍니다.

<div class="blue"></div>
<div class="outer">
  <div class="red"></div>
</div>
.blue,
.red {
  height: 50px;
  margin: 10px 0;
}

.blue {
  background: blue;
}

.red {
  background: red;
}

.outer {
  overflow: hidden; /* 새로운 BFC 형성! */
  background: transparent;
}

위쪽 파란색 박스의 margin-bottom: 10px과, 안쪽 빨간색 박스의 margin-top: 10px이 서로 만나지 못합니다. 빨간색 박스의 마진은 BFC를 형성한 .outer 박스 내부에 갇히게 되므로, 결과적으로 파란색 박스와 빨간색 박스 사이의 실제 거리는 의도했던 대로 20px이 됩니다.


명세서 (Specifications)

명세서 (Specification)
CSS Display Module Level 3
# block-formatting-context

같이 보기 (See also)


MDN 개선에 참여하기 (Help improve MDN)

이 페이지가 도움이 되셨나요?

기여하는 방법 알아보기 (Learn how to contribute)

이 페이지는 MDN 기여자들에 의해 2025년 11월 18일에 마지막으로 수정되었습니다 (MDN contributors).

profile
프론트에_가까운_풀스택_개발자

0개의 댓글