ブロック整形コンテキスト

ブロック整形コンテキスト (block formatting context, BFC) は、ウェブページにおける CSS の視覚的なレンダリングの一部です。ブロックボックスのレイアウトが行われ、浮動要素が他の要素と相互作用する領域です。

ブロック整形コンテキストは、以下のうちの少なくとも一つから生成されます。

  • 文書のルート要素 (<html>)
  • 浮動要素 (floatnone 以外である要素)
  • 絶対位置指定の要素 (positionabsolute または fixed である要素)
  • インラインブロック (display: inline-block である要素)
  • 表のセル (display: table-cell を持つ要素。これは HTML の表のセルの既定値です)
  • 表のキャプション (display: table-caption を持つ要素。HTMLの、表のキャプションの既定値です)
  • display: table, table-row, table-row-group, table-header-group, table-footer-group (つまりそれぞれ HTML の表、表の行、表の本体、表のヘッダー、表のフッターの既定値), inline-table のついた要素によって暗黙的に生成された無名の表のセル。
  • overflow の値が visible 以外であるブロック要素
  • display: flow-root
  • contain: layout, content, paint の付いた要素
  • フレックスアイテム (display: flex または inline-flex である要素の直接の子要素)、フレックスでもグリッドでもでもない場合
  • グリッドアイテム (display: grid または inline-grid である要素の直接の子要素)、フレックスでもグリッドでもでもない場合
  • 段組みコンテナー (column-count または column-widthauto ではない要素、 column-count: 1 の要素も含む)
  • column-span: all は、 column-span: all の要素が段組みコンテナーに含まれていなくても、常に新たな整形コンテキストを生成します (仕様変更, Chrome bug)。

整形コンテキストはレイアウトに影響を与えますが、通常はレイアウトを変更するのではなく、位置決めと浮動要素の解消のために新しいブロック整形コンテキストを作成します。これは、新しいブロック整形コンテキストを確立する要素が次のようになるからです。

  • 内部の浮動要素を収めます。
  • 外部の浮動要素を追いやります。
  • マージンの相殺を抑止します。

メモ: フレックス/グリッドコンテナー (display: flex/grid/inline-flex/inline-grid) は新しいフレックス/グリッド整形コンテキストを確立します。これは、レイアウト以外はブロック整形コンテキストに類似しています。フレックス/グリッドコンテナーの中に利用できる浮動子要素はありませんが、外部の浮動要素を除外したり、マージンの折りたたみを抑制したりすることはできます。

内部の浮動要素を収める

浮動小数点コンテンツと横に並んだコンテンツの高さを同じにします。

新しいBFC を作成する効果を見るために、これらのいくつかを見てみましょう。

以下の例では、borderが適用された <div> の中に浮動要素があります。その <div> のコンテンツは浮動要素の横に並んだ状態になっています。浮動要素のコンテンツは横に並んだコンテンツよりも高さがあるため、<div> の境界線が浮動要素を貫通してしまいます。フロー内とフローの外のガイドで説明しているように、浮動要素がフローから外れたので、 <div>backgroundborder には浮動要素はなく、コンテンツだけが保持されています。

overflow: auto の使用

overflow: auto を設定したり、初期値である overflow: visible 以外の値を設定すると、浮動要素を含む新しい BFC を作成することができます。これで、<div> がレイアウトの中のミニレイアウトになります。子要素はすべてこの中に含まれます。

新しい BFC を作成するために overflow を使用することの問題点は、overflow プロパティが、はみ出したコンテンツをどのように処理したいかをブラウザーに指示するためのものであることです。このプロパティを純粋に BFC を作成するために使用すると、不要なスクロールバーやクリップドシャドウが返されることがあるようです。さらに、将来的に開発者が読解できない可能性もあります。なぜそのために overflow を使用したのかがわからないかもしれないからです。もし overflow を使用するのであれば、コードにコメントをつけて説明するとよいでしょう。

display: flow-root の使用

より新しい値の display を使用すると、他の問題となりうる副作用なしに、新しいBFCを作成することができます。コンテナブロックに display: flow-root を使用すると、新しい BFC が作成されます。

display: flow-root;<div> に指定すると、コンテナーの中にあるすべてのものが、そのコンテナーのブロック整形コンテキストに参加し、浮動要素が要素の下部からはみ出ることはありません。

flow-root という値は、root 要素(ブラウザーでは <html> 要素)のように、その中にフローレイアウトのための新しいコンテキストを作成することを理解すれば、理にかなったものです。

HTML

html
<section>
  <div class="box">
    <div class="float">浮動ボックスです。</div>
    <p>コンテナー内のコンテンツです。</p>
  </div>
</section>
<section>
  <div class="box" style="overflow:auto">
    <div class="float">浮動ボックスです。</div>
    <p><code>overflow:auto</code> のコンテナー内のコンテンツです。</p>
  </div>
</section>
<section>
  <div class="box" style="display:flow-root">
    <div class="float">浮動ボックスです。</div>
    <p><code>display:flow-root</code> のコンテナー内のコンテンツです。</p>
  </div>
</section>

CSS

css
section {
  height: 150px;
}
.box {
  background-color: rgb(224 206 247);
  border: 5px solid rebeccapurple;
}
.box[style] {
  background-color: aliceblue;
  border: 5px solid steelblue;
}
.float {
  float: left;
  width: 200px;
  height: 100px;
  background-color: rgb(255 255 255 / 50%);
  border: 1px solid black;
  padding: 10px;
}

外部の浮動要素を除外する

以下の例では、 display:flow-root と浮動要素を使用して 2 列のレイアウトを実装しています。これは、新しい BFC を確立する通常のフロー内の要素が、その要素自身と同じブロック整形コンテキストにあるどの浮動要素のマージンボックスにも重ならないためです。

HTML

html
<section>
  <div class="float">外部の浮動要素の大きさを変えてみてください</div>
  <div class="box"><p>通常</p></div>
</section>
<section>
  <div class="float">外部の浮動要素の大きさを変えてみてください</div>
  <div class="box" style="display:flow-root">
    <p><code>display:flow-root</code></p>
  </div>
</section>

CSS

css
section {
  height: 150px;
}
.box {
  background-color: rgb(224 206 247);
  border: 5px solid rebeccapurple;
}
.box[style] {
  background-color: aliceblue;
  border: 5px solid steelblue;
}
.float {
  float: left;
  overflow: hidden; /* required by resize:both */
  resize: both;
  margin-right: 25px;
  width: 200px;
  height: 100px;
  background-color: rgb(255 255 255 / 75%);
  border: 1px solid black;
  padding: 10px;
}

inline-block で width:<percentage> を使用するよりも、この場合は右側の div の幅を指定する必要がありません。

なお、最近の CSS では、フレックスボックスの方が効率的に複数列のレイアウトを搭載することができます。

マージンの相殺を防止する

新しい BFC を作成すると、隣接する 2 つの div 間のマージンの相殺を避けることができます。

マージンの相殺の例

この例では、隣接する 2 つの <div> 要素があり、それぞれの垂直マージンは 10px です。マージンが相殺されるため、両要素間の垂直方向のギャップは 10 ピクセルとなり、期待される 20 ピクセルにはなりません。

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

.blue {
  background: blue;
}

.red {
  background: red;
}

マージンの相殺の防止

この例では、2つ目の <div> を外側の <div> で囲み、新しい BFC を作成し、マージンの相殺を防いでいます。

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

.blue {
  background: blue;
}

.red {
  background: red;
}

.outer {
  overflow: hidden;
  background: transparent;
}

仕様書

Specification
CSS Display Module Level 3
# block-formatting-context

関連情報