전체 목록
CSSMedium#81

BFC(Block Formatting Context)란 무엇이며 어떤 상황에서 생성되나요?

#CSS#BFC#레이아웃#렌더링
힌트

float 해제나 margin 겹침 문제 해결과 관련이 있습니다.

정답 및 해설

BFC(Block Formatting Context)란 무엇이며 어떤 상황에서 생성되나요?

BFC(Block Formatting Context)는 블록 레벨 요소들이 독립적으로 렌더링되는 레이아웃 컨텍스트입니다. BFC 내부의 요소들은 외부 요소와 완전히 격리되어 독자적인 레이아웃 규칙이 적용됩니다. Float 정리, 마진 병합 방지, 요소 겹침 방지 등 CSS 레이아웃에서 발생하는 여러 문제를 해결하는 핵심 개념입니다.

BFC의 특성

BFC가 생성되면 다음과 같은 규칙이 해당 영역 내에 적용됩니다.

  1. BFC 내부의 블록 요소들은 수직으로 쌓입니다
  2. BFC 내부 요소와 외부 요소 간의 마진 병합이 발생하지 않습니다
  3. BFC는 내부의 float 요소를 포함합니다 (높이 붕괴 방지)
  4. BFC 영역은 float 요소와 겹치지 않습니다

BFC 생성 조건

/* 1. overflow: hidden / scroll / auto (visible 제외) */
.bfc-overflow {
    overflow: hidden;
}

/* 2. display: flex / grid / inline-block / table-cell / table-caption */
.bfc-flex {
    display: flex;
}
.bfc-grid {
    display: grid;
}
.bfc-inline-block {
    display: inline-block;
}

/* 3. position: absolute / fixed */
.bfc-absolute {
    position: absolute;
}
.bfc-fixed {
    position: fixed;
}

/* 4. float 요소 (none이 아닌 값) */
.bfc-float {
    float: left;
}

/* 5. contain: layout / content / paint */
.bfc-contain {
    contain: layout;
}

/* 6. display: flow-root (명시적 BFC 생성, 부작용 없음) */
.bfc-flow-root {
    display: flow-root; /* 가장 권장되는 방법 */
}

활용 1: Float 부모 높이 붕괴 방지

문제 상황

float 요소는 일반 문서 흐름에서 벗어나기 때문에, 부모 요소가 float 자식의 높이를 인식하지 못합니다.

<div class="container">
    <div class="float-item">Float 요소</div>
    <div class="float-item">Float 요소</div>
</div>
<p>다음 단락</p>
/* 문제 발생 */
.container {
    border: 2px solid red;
    /* 부모의 높이가 0이 됨! */
}

.float-item {
    float: left;
    width: 100px;
    height: 100px;
    background: lightblue;
}
┌──────────────────────────────┐  ← container (높이 0)
│ ┌─────────┐ ┌─────────┐     │
│ │ float1  │ │ float2  │     │
│ └─────────┘ └─────────┘     │
└──────────────────────────────┘
다음 단락이 float 아래로 올라옴

해결 방법 비교

/* 방법 1: clearfix (전통적 방법) */
.container::after {
    content: "";
    display: block;
    clear: both;
}

/* 방법 2: overflow: hidden (BFC 생성) */
.container {
    overflow: hidden; /* BFC 생성 → float 포함 */
}

/* 방법 3: display: flow-root (권장, 부작용 없음) */
.container {
    display: flow-root; /* 명시적으로 BFC 생성 */
}
/* display: flow-root 적용 후 */
┌──────────────────────────────┐
│ ┌─────────┐ ┌─────────┐     │  ← container가 float 포함
│ │ float1  │ │ float2  │     │
│ └─────────┘ └─────────┘     │
└──────────────────────────────┘
다음 단락이 정상 위치에 배치됨

활용 2: 마진 병합(Margin Collapse) 방지

인접한 블록 요소 간 마진 병합

<div class="box1">박스1 (margin-bottom: 30px)</div>
<div class="box2">박스2 (margin-top: 20px)</div>
/* 마진 병합 발생: 두 박스 사이 간격은 50px이 아닌 30px */
.box1 { margin-bottom: 30px; }
.box2 { margin-top: 20px; }
/* 결과: max(30px, 20px) = 30px (병합됨) */
┌────────┐
│  box1  │
└────────┘
   30px  ← 50px이 아닌 30px만 적용됨
┌────────┐
│  box2  │
└────────┘

BFC로 마진 병합 방지

<div class="box1">박스1</div>
<div class="bfc-wrapper">
    <div class="box2">박스2</div>
</div>
.box1 { margin-bottom: 30px; }
.bfc-wrapper {
    overflow: hidden; /* BFC 생성 → 내부 box2의 마진이 외부로 나오지 않음 */
}
.box2 { margin-top: 20px; }
/* 결과: box1과 box2 사이 간격 = 30px + 20px = 50px */

부모-자식 마진 병합

<div class="parent">
    <div class="child">자식 요소</div>
</div>
/* 문제: 부모에 border/padding이 없으면 자식의 margin-top이 부모 밖으로 튀어나옴 */
.parent { background: lightgray; }
.child { margin-top: 30px; } /* 부모까지 함께 내려감 */

/* 해결 1: 부모에 padding 추가 */
.parent { padding-top: 1px; }

/* 해결 2: 부모에 border 추가 */
.parent { border-top: 1px solid transparent; }

/* 해결 3: 부모에 BFC 생성 */
.parent { display: flow-root; }

활용 3: Float 요소와 겹침 방지

문제: 일반 블록 요소가 float 요소 아래로 파고듦

<div class="float-box">Float 박스</div>
<div class="content">긴 텍스트 콘텐츠... 이 내용이 float 박스와 겹칩니다.</div>
.float-box {
    float: left;
    width: 150px;
    height: 100px;
    background: lightblue;
    margin-right: 20px;
}

/* 문제: content가 float 아래로 파고듦 */
.content {
    background: lightyellow;
    /* 텍스트는 float를 피하지만 배경색이 float 아래에 깔림 */
}
┌─────────────────────────────────────────┐
│ ┌──────────┐ 텍스트는 여기서 시작...    │
│ │  float   │ 텍스트 내용 계속됩니다     │
│ │   box    │ 긴 텍스트가 있을 때        │
│ └──────────┘ float 아래 영역에도        │
│ content 배경이 float 아래까지 깔림      │
└─────────────────────────────────────────┘

BFC로 해결

/* BFC 생성으로 float 요소와 겹침 방지 */
.content {
    overflow: hidden; /* 또는 display: flow-root */
    background: lightyellow;
}
┌─────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────────────────┐   │
│ │  float   │ │  content (BFC)       │   │
│ │   box    │ │  텍스트 내용이 여기  │   │
│ └──────────┘ │  정상적으로 배치됨   │   │
│              └──────────────────────┘   │
└─────────────────────────────────────────┘

display: flow-root vs overflow: hidden

/* overflow: hidden의 부작용 */
.container {
    overflow: hidden; /* BFC 생성 */
    /* 문제: 자식 요소가 영역 밖으로 나가면 잘림 */
    /* 드롭다운 메뉴, 툴팁 등이 잘릴 수 있음 */
}

/* display: flow-root: 부작용 없음 (권장) */
.container {
    display: flow-root; /* 명시적 BFC, 오버플로 영향 없음 */
}

브라우저 지원

/* display: flow-root 미지원 브라우저를 위한 폴백 */
.container {
    overflow: hidden; /* 폴백 */
}

@supports (display: flow-root) {
    .container {
        overflow: initial;
        display: flow-root;
    }
}

현대 CSS에서의 BFC

Flexbox와 Grid 컨테이너는 자동으로 BFC를 생성합니다.

/* Flexbox: 자동으로 BFC 생성 */
.flex-container {
    display: flex;
    /* float 포함, 마진 병합 방지 등 BFC 특성 자동 적용 */
}

/* Grid: 자동으로 BFC 생성 */
.grid-container {
    display: grid;
}

/* 따라서 현대 레이아웃에서는 BFC 문제가 덜 발생 */
/* float 기반 레거시 코드를 다룰 때 특히 중요 */

실전 예제: 미디어 오브젝트 패턴

<div class="media">
    <img class="media-image" src="avatar.png" alt="프로필">
    <div class="media-body">
        <h3>사용자 이름</h3>
        <p>이것은 미디어 오브젝트 패턴입니다. 이미지 옆에 텍스트가 배치되는 일반적인 UI 패턴입니다.</p>
    </div>
</div>
.media {
    display: flow-root; /* BFC 생성 → float 포함 */
}

.media-image {
    float: left;
    width: 60px;
    height: 60px;
    margin-right: 16px;
}

.media-body {
    overflow: hidden; /* BFC 생성 → 이미지와 겹침 방지 */
    /* 또는: display: flow-root */
}

요약 표

특성설명해결하는 문제
Float 포함BFC 내 float 요소의 높이를 포함부모 높이 붕괴
마진 격리BFC 내부/외부 마진 병합 방지예상치 못한 마진 병합
Float 겹침 방지BFC 영역은 float와 겹치지 않음콘텐츠가 float 아래로 파고듦
BFC 생성 방법부작용권장도
display: flow-root없음최우선 권장
display: flex / grid자식 레이아웃 변경레이아웃 목적이면 OK
overflow: hidden콘텐츠 잘림 가능신중히 사용
overflow: auto/scroll스크롤바 생성 가능필요시 사용
position: absolute/fixed문서 흐름에서 벗어남BFC 목적으로는 비권장
float문서 흐름에서 벗어남BFC 목적으로는 비권장