對BFC的理解

来源:https://www.cnblogs.com/beckyyyy/archive/2023/08/30/17668489.html
-Advertisement-
Play Games

BFC作為前端面試佈局方面的重要考點,開發者有必要進行深入的瞭解,通過對BFC的深入理解,也能幫助我們解決佈局中的很多問題。 ...


在前端的面試中,相對JavaScript而言,CSS佈局方面考察的內容會相對少一些,其中BFC是佈局樣式方面常考的一個考點。

什麼是BFC

BFC,全稱為Block Formatting Context,翻譯過來即塊格式化上下文。

之前在其他文章中看到的說明是,網頁上一個獨立且隔離的渲染區域。現在呢,我稍微查閱了一些官方的信息。

在瞭解BFC之前,我們需要先瞭解一些其他概念:

包含塊(containing block)

containing block

A rectangle that forms the basis of sizing and positioning for the boxes associated with it. Notably, a containing block is not a box (it is a rectangle), however it is often derived from the dimensions of a box. Each box is given a position with respect to its containing block, but it is not confined by this containing block; it can overflow. The phrase “a box’s containing block” means “the containing block in which the box lives,” not the one it generates.

In general, the edges of a box act as the containing block for descendant boxes; we say that a box “establishes” the containing block for its descendants. If properties of a containing block are referenced, they reference the values on the box that generated the containing block. (For the initial containing block, values are taken from the root element unless otherwise specified.)

簡單翻譯一下:

包含塊

一個矩形,是與之相關的盒子的尺寸和定位的基礎。值得註意的是,包含塊並不是一個盒子(它是一個矩形),但它通常是從盒子的尺寸中衍生出來的。每個盒子都有一個相對於其包含塊的位置,但它不受包含塊的限制,可以溢出。“盒子的包含塊"指的是 "盒子所在的包含塊",而不是盒子產生的包含塊。
一般來說,一個盒子的邊緣作為後代盒子的包含塊;我們說一個盒子為它的後代 "建立"了包含塊。如果引用了包含塊的屬性,則引用的是生成包含塊的盒子的值。(對於初始包含塊,除非另有說明,否則其值取自根元素)。

從上述定義中,我們可以簡單認為一個盒子其產生的包含塊就是除了盒子的margin、border和padding以外最內部的那塊區域。

邊緣(edge)

edge

The perimeter of each of the four areas (content, padding, border, and margin) is called an edge

邊緣

四個區域(內容、填充、邊框和外邊距)中每個區域的周長稱為邊緣

邊緣edge,定義了盒模型中的四個邊緣。

initial containing block

The containing block of the root element. The initial containing block establishes a block formatting context.

初始包含塊

指根元素的包含塊。初始包含塊建立了塊格式上下文。

格式化上下文(FC,formatting context)

formatting context

A formatting context is the environment into which a set of related boxes are laid out. Different formatting contexts lay out their boxes according to different rules. For example, a flex formatting context lays out boxes according to the flex layout rules [CSS-FLEXBOX-1], whereas a block formatting context lays out boxes according to the block-and-inline layout rules [CSS2]. Additionally, some types of formatting contexts interleave and co-exist: for example, an inline formatting context exists within and interacts with the block formatting context of the element that establishes it, and a ruby container overlays a ruby formatting context over the inline formatting context in which its ruby base container participates.

A box either establishes a new independent formatting context or continues the formatting context of its containing block. In some cases, it might additionally establish a new (non-independent) co-existing formatting context. Unless otherwise specified, however, establishing a new formatting context creates an independent formatting context. The type of formatting context established by the box is determined by its inner display type. E.g. a grid container establishes a new grid formatting context, a ruby container establishes a new ruby formatting context, and a block container can establish a new block formatting context and/or a new inline formatting context. See the display property.

格式化上下文
格式化上下文是一組相關盒子佈局所在的環境。不同的格式上下文根據不同的規則佈局盒子。例如,彈性格式上下文根據彈性佈局規則[CSS-FLEXBOX-1]佈局方框,而塊格式上下文則根據塊和行內佈局規則[CSS2]佈局盒子。此外,某些類型的格式化上下文會交錯並存:例如,行內格式化上下文存在於建立行內格式化上下文的元素的塊格式化上下文中,並與之交互;ruby容器會在其ruby基本容器所參與的行內格式化上下文上疊加ruby格式化上下文。
盒子要麼建立新的獨立格式上下文,要麼延續其包含塊的格式上下文。在某些情況下,盒子可能會額外建立一個新的(非獨立的)共存格式上下文。除非另有規定,否則建立新的格式上下文會創建一個獨立的格式上下文。盒子建立的格式上下文類型由其內部顯示類型決定。例如,網格容器會建立新的網格格式上下文,ruby容器會建立新的ruby格式上下文,而塊容器可以建立新的塊格式上下文和/或新的行內格式上下文。請參閱顯示屬性。

由上述定義可知每種FC都有其不同於其他FC的佈局規則,由此可知每種FC的創建是聲明瞭一個應用其佈局規則的區域。

而盒子的FC類型由其內部顯示類型決定,即display屬性的第二個值。

BFC

先看W3C中的定義:Block formatting contexts

Boxes in the normal flow belong to a formatting context, which may be block or inline, but not both simultaneously. Block-level boxes participate in a block formatting context. Inline-level boxes participate in an inline formatting context.

Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.

In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).

翻譯過來大致是下麵的意思:

正常流中的盒子屬於格式化上下文,可以是塊或行內,但不能同時是塊和行內。塊級盒子屬於塊格式上下文,行內級盒子屬於行內格式上下文。

浮動元素、絕對定位元素、非塊盒子的塊容器(如inline-block、table-cells,以及table-captions),以及 'overflow' 不是 'visible' 的塊盒子(除非該值已傳播到viewport),都會為其內容建立新的塊格式上下文。

在塊格式化上下文中,盒子從包含塊的頂部開始一個接一個地垂直排列。兩個同胞盒子之間的垂直距離由 'margin' 屬性決定。在塊格式上下文中相鄰塊級盒子之間的垂直margin會摺疊。

在塊格式化上下文中,每個盒子的左外緣與包含塊的左緣相接(對於自右向左的格式,則是右緣相接)。即使在浮動的情況下(儘管盒子的行盒可能因浮動而縮小)也是如此,除非盒子建立了新的塊格式化上下文(在這種情況下,盒子自身可能會因浮動而變窄)。

其實看完這個定義我剛開始還有一點疑惑,細想了一下最後一段的意思可以對應以下情況:

前一個是浮動元素,後面緊跟的元素也會與盒子的左緣(或右緣)相接(也就是這個元素與前面的浮動元素會發生重疊),為了防止這個事情發生,可以為後面這個元素創建新的BFC,這樣這個新的BFC就不會與外部BFC的左緣(或右緣)相接了,同時這個元素會因為前一個浮動元素的存在,而寬度變窄。

MDN中給出的定義:Block formatting context

這裡給出的定義就是比較簡短的一句話,翻譯過來是:

塊格式化上下文(BFC)是網頁的可視化CSS渲染的一部分。它是塊盒子佈局的區域,也是浮動元素與其他元素交互的區域。

簡而言之,就是塊盒子內部的佈局區域,既然是內部,也就與外部相隔離開,並且在這個區域內,浮動元素會與其他元素產生交互。

觸發條件

由以上定義可知,容器滿足以下條件之一,其產生的包含塊便可以形成BFC:

  • 為文檔的根元素(<html>
  • 正常流中的塊級盒子
  • 浮動元素
  • 絕對定位元素
  • 非塊盒子的塊容器(如inline-block、table-cells,以及table-captions)
  • overflow不是visible的塊盒子
  • displayflow-root的元素(the display property)

除此之外,MDN還有其他補充(應該都屬於對非塊盒子的塊容器的補充):

  • 表格單元格(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或clip的塊元素
  • contain屬性為layout、content或paint的元素
  • 彈性項(display屬性為flex或inline-flex的元素的直接子元素),如果它們本身並非flex或grid或table容器
  • 網格項(display屬性為grid或inline-grid的元素的直接子元素),如果它們本身並非flex或grid或table容器
  • 多列容器(column-countcolumn-width屬性不為auto的元素,包括設置column-count:1的元素)
  • column-span:all元素應始終創建新的格式化上下文,即使其不包含在多列容器中

佈局規則

同時根據以上的定義,還可以得出BFC內部的內容遵循以下佈局規則:

  • BFC的內容包含在包含塊內
  • 內部的盒子從包含塊的頂部開始一個接一個地垂直排列
  • 兩個同胞盒子之間的垂直距離由'margin'屬性決定
  • 相鄰塊級盒子之間的垂直'margin'會摺疊
  • 每個盒子的左外緣與包含塊的左緣相接(對於自右向左的格式,則是右緣相接)。即使在浮動情況下也是如此(儘管盒子的行盒子可能因浮動而縮小),除非該盒子建立了新的塊格式化上下文(在這種情況下,盒子自身可能會因浮動而變窄)

同時BFC自身不會與同級的浮動元素髮生重疊

應用場景

至此,就大致瞭解了BFC是什麼,其觸發形成機制,以及其內部的佈局規則。

但通常情況下我們不會僅僅為了更改佈局去創建新的BFC,而是為瞭解決特定的問題來創建BFC,比如定位和清除浮動,因為建立了新BFC的容器將可以:

  • 包含內部浮動元素(也就是浮動元素不會溢出容器之外)
  • 排除外部浮動元素(利用BFC不會與同級浮動區域重疊的規則)
  • 抑制margin摺疊(通過在BFC的內部創建新的BFC使得其中相鄰盒子的margin不發生摺疊)

以下就是MDN中的幾個例子:

包含內部浮動元素

<section>
  <div class="box">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the container.</p>
  </div>
</section>
section {
  height: 150px;
}
.box {
  background-color: rgb(224, 206, 247);
  border: 5px solid rebeccapurple;
}
.float {
  float: left;
  width: 200px;
  height: 100px;
  background-color: rgba(255, 255, 255, 0.5);
  border: 1px solid black;
  padding: 10px;
}

這其實也是一種清除浮動、解決高度坍塌的方案,在過去有些前端開發人員會給.box這個div設置overflow: auto;或者hidden來使其內部形成BFC,這是一種方式,但這種解決方式存在一個問題,就是對於後續的開發者來說,他們可能不清楚為什麼要使用overflow,如果要這麼用,最好用註釋說明清楚。

現在有一個新的displayflow-root可以讓我們用來創建新的BFC,用它會更好,因為從字面上更好理解,創建的容器為其內部的流式佈局創建新的上下文的行為類似於root元素(也就是瀏覽器中的<html>元素)。

排除外部浮動元素

這個例子中我們要實現雙列佈局,當然在現在CSS中,用彈性盒子實現更方便,但我們也可以通過BFC來實現。

在上一個例子中,可以看到浮動元素與後面的p元素重疊了,如果我們不想他們重疊,希望他們可以形成雙列佈局,就可以通過建立新的BFC來實現,比如給p元素套上一個div同時給其設置display: flow-root;來手動觸發BFC的形成,因為BFC不會與任何同級浮動元素的margin盒子發生重疊。

<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
section {
  height: 150px;
}
.box {
  background-color: rgb(224, 206, 247);
  border: 5px solid rebeccapurple;
}
.float {
  float: left;
  overflow: hidden; /* required by resize:both */
  resize: both;
  margin-right: 25px;
  width: 200px;
  height: 100px;
  background-color: rgba(255, 255, 255, 0.75);
  border: 1px solid black;
  padding: 10px;
}

從而達到防止浮動元素與其他元素重疊。

阻止邊距摺疊

因為BFC內部的佈局規則是相鄰盒子間的垂直margin會摺疊,如果我們不想起發生摺疊,也可以利用創建BFC的方式來達到目的。

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

.blue {
  background: blue;
}

.red {
  background: red;
}

如果不想使紅色和藍色兩個元素的margin發生摺疊,就可以給紅色元素套上一個div並使其創建BFC,這個BFC就是一個獨立渲染的區域,這樣兩個元素的垂直margin就不會發生摺疊了。

總結

當我們使用Chrome的開發者工具,可以查看到網頁內的塊狀元素其對應的盒模型,margin、border、padding,以及最裡層的content,獨立的佈局渲染區域指的應該就是content這部分。

創建BFC的目的,就是想把容器內部的內容限定在這部分區域中,而不與外部元素產生作用,比如上個例子中阻止垂直margin摺疊,就是把紅色元素限定在一個新的BFC中,從而不與外部的藍色元素髮生作用,這樣就不會出現margin摺疊了。

參考資料

包含塊(containing block)

邊緣(edge)

W3C:Block formatting contexts

MDN:Block formatting context

本文來自博客園,作者:beckyye,轉載請註明原文鏈接:https://www.cnblogs.com/beckyyyy/p/17668489.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在這個燥熱的夏天,又突然收到告警,分庫分表的主鍵衝突了,這還能忍?不,堅決不能忍,必須解決掉!後面咱們慢慢道來是如何破局的,如何走了一條坎坷路…… ...
  • - 0.寫在前面 - 1.準備工作 - 1.1 準備Docker環境 - 1.2 下載源碼包 - 1.3 修改MySQL Shell源碼包 - 1.4 編譯相關軟體包 - 2.準備編譯MySQL Shell - 2.1 編譯MySQL 8.0.32 - 2.2 編譯MySQL Shell 8.0.3 ...
  • 今天來說一個老生常談的問題,來看一個實際案例:業務中往往都會通過緩存來提高查詢效率,降低資料庫的壓力,尤其是在分散式高併發場景下,大量的請求直接訪問Mysql很容易造成性能問題。 ...
  • 在mybatis的xml中使用MySQL的`DATE_FORMAT` 函數可以將日期類型的數據格式化為字元串。然而,儘管這個函數很方便,但在處理大量數據時可能會引起性能問題,特別是在複雜查詢中。這是因為 `DATE_FORMAT` 函數的計算是在資料庫引擎層級進行的,而不是在應用程式代碼中。 以下是 ...
  • 原文地址: https://www.mssqltips.com/sqlservertip/3572/recovering-a-sql-server-tde-encrypted-database-successfully/ 問題: 我的任務是在具有敏感信息的SQL Server資料庫上設置透明數據加密 ...
  • ## 前言 最近接到一個任務是將一個unity開發的游戲接入到現有的Android項目里,然後在現有的App實現點擊一個按鈕打開游戲,並且在游戲內提供一個可以退出到App的按鈕。 整體需求是很明確的,難點主要有兩個: 1. 我們公司是做應用開發的,沒有任何游戲開發的技能儲備。 2. 在游戲中需要和N ...
  • 本章提供了 HarmonyOS 的基礎知識,包括定義、發展歷程、特點、架構和與其他操作系統的比較。這為後續的開發工作打下了堅實的基礎。 ...
  • # 背景 通常情況下,當我們需要從父組件向子組件傳遞數據時,會使用 **props**。想象一下這樣的結構:有一些多層級嵌套的組件,形成了一顆巨大的組件樹,而某個深層的子組件需要一個較遠的祖先組件中的部分數據。在這種情況下,如果僅使用 props 則必須將其沿著組件鏈逐級傳遞下去,這會非常麻煩: ! ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...