同學們好,我是來自 《技術銀河》的 💎 三鑽 。
這一週我們重新回到《重學 CSS》系列,之前的文章中我們重新學習了《 CSS 選擇器》和《 CSS 語法與規則》。接下來我們就一起來講講 CSS 裡面的排版與正常流。
在講解 CSS 當中的排版和正常流的時候,我們會按照屬性的一些邏輯關係來分成幾個部分來講解與學習。
講到排版,我們需要引入的第一個概念就是 「盒
」。之前我們在《模擬瀏覽器》和之前的一些 CSS 的文章中都講到了排版相關的概念。
而我們真正去講到排版的時候,我們需要用到的單位一定就是 「盒
」。
在真正進入詳細瞭解 「盒」 的概念之前,我們先來做認識一下 3 個比較容易混交的概念。
HTML 程式碼中可以書寫開始
標籤
,結束標籤
,和自封閉標籤
。
標籤是一個原始碼的概念,所以方式我們提到在 HTML 程式碼中寫的肯定都是標籤。
一對起止
標籤
,表示一個元素
。
元素是存在我們腦子裡的一個概念,它是語意領域的一個概念,所以一對起止標籤它一定是表示一個我們腦子裡面的概念。
DOM 樹中儲存的是
元素
和其他型別的節點 ( Node )。
DOM 樹中儲存的不全是元素,因為DOM 樹中儲存的東西叫節點 Node
,所以元素只是是節點的一種。
比如說我們的文位元組點也是節點,但他並不是元素。再比如我們的註釋節點,它也是節點但是它也不是元素。當然還有 CDATA 節點,還有 processing-instruction,DTD等這些都是會存入 DOM 樹的,當時它們都並不是元素。
很多同學的理解,DOM 樹中儲存的都是元素,不過這樣也沒有錯。因為其他的節點相對來說都沒有那麼重要。
CSS 選擇器中的是
元素
。
其實這裡還可以加一個 「或」,在《CSS 選擇器》中講到的,CSS 選擇器選中的是元素或者是偽元素
。
CSS 選擇器中的
元素
,在排版時可能產生多個盒
。
這個地方是大家需要注意到的一個概念,CSS 選擇器選中的元素,它不一定和盒是一一對應的關係。它有可能是一對多的關係的。但是有盒一般來說必定是有對應的元素的。我們不可能無中生有產生一個元素,即使是號稱是無中生有的偽元素也是依附於一個選中的元素產生的。
排版和渲染的基本單位是
盒
在我們的《模擬瀏覽器》的實現過程中,我們的排版盒渲染都是直接拿元素當盒去用了。但是這是一個很粗糙的做法,在實際上我們很多元素都會產生多個盒。
比如說 inline
元素就會因為分行而產生多個盒。又比如說帶有偽元素,被偽元素選擇器選中的元素也會生成多個盒。所以我們排版盒渲染的基本單位都是盒。
既然我們講到盒,我們都會講到大名鼎鼎的 「盒模型
」。我相信很多同學都知道盒模型,並且也學習過盒模型。但是也有很多同學可能沒有理清楚摸透這個概念,所以就會導致不知道什麼是盒模型,更不知道"盒
"這個概念是從何而來。
上面我們已經講清楚了盒是從,標籤到元素,到 CSS 選擇器到如何產生了盒。所以對盒的來龍去脈我們都很清楚了,所以這裡我們就可以開始詳細的去了解盒模型的概念。
盒模型是我們排版的時候所用的一種基本單位
盒模型中的"盒",不光是有一個寬和一個高。不像在《模擬瀏覽器》部分裡面那樣非常的好算,其實它還是挺複雜的。
盒模型是一個多層的結構,從裡面到外面分為:
content
,也就是我們的內容
padding
,也就是內邊距
margin
,也就是外邊距
盒模型裡面的 寬 (width) 是有講究的,盒子的寬度是有可能被 box-sizing
屬性所影響的。最常見的兩個值就是:
設定的 width
屬性只包含 content
的內容的空間。也就是說:
盒子佔用的空間
= content 的大小
+ padding 的大小
+ border 的大小
+ margin 的大小
怎麼聽起來就是一臉懵的感覺。😂
其實更接近人類的理解就是,我們在 CSS 中設定的
width
屬性只對最裡面的content
的空間有效。其餘的padding
,border
和margin
都會疊加到盒子的佔用空間。
那這個為什麼程式設計師都說這種盒子是 「反人類」 的呢?如果很早起就接觸到 HTML 和 CSS 的同學應該都知道這麼一個讓人痛不欲生的場景:
在排版時候我們明明設定好這個盒子的寬度,但是最後加了 border 和 padding 就讓盒子 「變大」 了。所以最後我們要反過來重新計算 width 屬性來保證這個盒子是我們想要的寬度。
對!可能很多用習慣 box-sizing: border-box
的同學,早就忘記了這些痛苦的日子了。但是事實上這個設計理念就是有點反人類的。所以後面就打了一個修補程式來拯救我們程式設計師,加入了 border-box
。從此之後程式設計師就又可以開心的敲程式碼了。
使用border-box
,我們的 width 就包含了 padding 和 border 的尺寸了。回去看看我們盒模型的圖,我們可以看到border-box
的黃色線括著的區域,它所佔據的空間和範圍。
這樣當我們給一個盒,padding 和 border 的時候,就不會影響我們給予盒子的 width。這樣我們就可以保證我們盒子在沒有 margin 的時候它所佔據的空間就是與我們 width 一致的。
呈現出來的效果就是 padding 和 border 都會往內擠壓空間,而不會影響盒子的寬度。
這裡我們就講完盒模型了,我們就發現它所影響的屬性就是
margin
,padding
,border
,box-sizing
這幾個屬性。這些都是影響我們盒模型的總體尺寸,在排版中會影響著這個盒模型所佔據的範圍。
CSS 的排版其實是有三代的排版技術的:
正常流
Flex
的排版Grid
的排版CSS Houdini
,可能更接近的是 3.5 代,它是一種完全自由的,允許使用 JavaScript 干預的排版目前主流都是在使用 flex
佈局。相比 flex
,其實正常流並沒有變得更簡單,反而是更復雜了。
不過挺有意思的是,flex 它比前面的第一代的排版技術要簡單,比他後面一代的 grid 也簡單。個人認為 flex 是最簡單並且最容易理解的一代排版技術。
正常流呢,其實它能力最差,但是反而他的機制很複雜。
如果我們看到上面這個圖,可能有一些同學知道是什麼,有一些同學完全不知道他在幹什麼。其實這個就是 80 年代印刷廠工人在進行排版工作。
這個傳統的排版技術,其實與我們現在網頁的layout
是息息相關的。在很多文章中,我們會把layout
翻譯成排版
,有時候也會翻譯成佈局
。但是我個人也覺得翻譯成排版
是最貼切的。因為 CSS 當中的layout
是源自於傳統的排版技術。
傳統的排版方式,我們需要先把字版放入一個一個字框裡面,按照文字的順序排列號,然後再把這些字框一個一個的排列進我們的排版框裡面。
所以所謂排版就給我們所有可見的東西放到正確的位置上去。而在 HTML 裡面,我們是有 「盒」 這樣一個東西,在 CSS 的排版裡我們只排兩樣東西
。
一切 CSS 的排版,都不會逃出這
盒
與文字
這樣兩東西。所以我們的排版就是給每一個文字安排到正確的位置上,然後給每一個盒安排到正確的位置上。
在不考慮盒模型的情況下,我們需要關注的就是位置和尺寸,所以排版中並沒有什麼特殊的內容。
我們在進入正常流之前,我們一起來先思考一下我們寫字的時候是怎麼寫的。
其實我們寫字的時候,某種意義上講也是一個排版的過程。很多同學們小時候寫作文的時候都會用到上面這種有格子的稿紙。我們都記得這個作文稿紙上都是有一個一個的格子的,其實這相當於一個已經有了排版。
如果在我們稿紙上沒有格子呢,我們就要自己來決定每一行要寫多少個字,每一個字有多高,然後怎麼分段呢?等等這些問題,都是在我們小時候寫字時需要關注的。
那麼我們來總結一下寫字有哪些規則呢?
其實以上的這些規則也就是我們說的 「正常流 ( Normal Flow )
」,所以正常流為什麼正常呢?因為正常流就是與我們平時書寫文字的習慣一致。無論是中文也好,英文也好,它們都是遵循這種自然的排版方式的。
有一些我們早期進入前端的同學,就會發現其實正常流裡面,有很多特別不正常的東西,特別的反直覺,反人類的東西。為什麼這麼奇怪的東西要叫正常流呢?
很負責任的告訴大家,其實一點都不奇怪。如果我們知道前端的 HTML 和 CSS 的排版概念都是源自於專業排版知識,而這些排版使用方式如果出現在我們的書籍裡面,我們都會覺得挺自然的。但是真正讓我們去理解這些知識,我們都會覺得很困難。
這個就可以追溯到 HTML 最早期整個的排版設計,都是從文字出版行業過來的專家所做的。所以它使用的思路都是那個時代的一個專業的思路。跟我們自然人腦子裡面的理解,可能就會有一些差異了。
接下來我們就正式進入正常流的排版講解。
正常流排版的整個過程,與實現 flex 的過程比較類似,有這幾個步驟:
我們發現其實這個與我們 flex 的排版非常的像。其實我們會發現所有的排版演演算法,基本上都是差不多的。不論是哪個軟體,哪個規則,它們都是這麼幾個步驟。
接下來我們來看看具體的一個排布規則:
當文字和盒在一行裡面的時候,它們是會從左向右排布的。假設我們先不考慮 writing-mode 的事情,這裡所說的從左向右排就意味著文字和盒有一個對齊的規則。這個就比我們小時候寫作文的那個格子要複雜了。
在寫作文的格子稿紙上,我們是不需要考慮圖片和其他元素與我們的文字混排的情況的。我們在寫作文的時候不會寫著寫著在旁邊話一個插圖什麼的。但是我們發現書裡面是有的,特別是專業的書籍基本上都是圖文內容。
這些書裡面都是寫著寫著就會插入一個圖表,這些圖表有的是在行內放一個小的圖片,有的是裡面加一個小圖示。這些都是行內盒,更準確的說這叫 inline-level-box
,就是行內級別的盒。
還有一些我們需要插入一個大圖,比如說一個統計的資料,因為這種一般來說高度都比較高,放在一行裡面會很奇怪。所以這個時候我們會讓它單獨佔一行。這種型別的盒,我們就把它稱為 block-level-box
,也叫塊級盒。
所以文字和 inline level 行內的盒排出來的行,我們就叫做 「行盒 ( line-box )
」,然後一個自然的正常流,整體來看就是一個個的 line-box
和 block-level-box
的從上到下的擺佈。如果沒有 block-level-box
,那麼都是行盒從上到下排布。而每個行盒的內部都是從左到右的排布。
其實上面講到的兩種情況都是有一個名字的。
BFC
—— Block level formatting context (塊級格式化上下文)IFC
—— Inline level formatting context (行內級格式化上下文)很多在比較早期學習前端,甚至在一些 「0 基礎」 的班裡面學前端的同學,都會聽說過 「塊級元素」 和 「行內元素」 兩種說法。其實與我們講到的 BFC 和 IFC 就是這個概念最原本的意思。
小時候我們在學習英文的時候,就會使用過這種 4 線本的格式來書寫英文。
我們可以注意到在書寫 example
這個英文的時候,我們可以看到 e
,x
,a
,m
都是在一行之內的。但是 p
和 l
就不一樣了。p
的尾巴是稍微往下突出的,而 l
它的頭部是稍微往上突出的。
所以英文的字母呢,總是會有一些字母會往上或者往下伸出一塊的。這個也是英文書寫的一些規範,因為遵循這些規範才能讓我們的字母在書寫的時候好看。基本上所有字母的下緣都是需要對準一條線的,那就是倒數第二條錢(在圖片中的黃色的線)。
這條線也叫 「
基線
」,而這個規則就叫做 「基線對齊
」。
其實各國的文字都是有一條基線對齊的規則,但是不同的國家的文字依賴的基線的位置不一樣。比如說中文需要和英文混排的話,就會出現一個基線的偏移。
像中文這種型別的字,都會以上文下文這種邊緣作為基礎線去對齊的。但是我們也是可以認為這些型別的文字也是基於 基線 (baseline)
對齊的。我們可以理解為它們只是帶了一定的偏移。
接下來我們一起來了解一下,一個字形它是怎麼樣去定義的。在之前的文章中我們有講到一些字元集這方面的基礎知識。其實一個字元就是一個碼點,以為著它的形狀是由我們的字型來決定的。
下面的兩張圖是來自於一個著名的 C++ 的底層庫,叫做 freeType
。這個庫就是處理各種字型檔案成為抽象,並且它是一個開源界大部分的軟體都會去使用的一個字型庫。
這個庫中,它從字型中抽象出這麼一個定義:
任何一個文字,都是有一個寬和高,除此之外還有一條基線的定義。(如何沒有這個基線的定義,我們的字型是不成立的,也沒有辦法用它來進行排版)。這個定義就叫做
Glyph Metrics
。
我們先來看看第一張圖:
首先我們看到 origin
,也就是一個字型的原點。而原點標識的位置就是我們文字的基線的位置,而這個文字都是以基線作為原點的座標,然後再用這個座標來定義這個文字的位置。
所以說基線就是在 x = 0
這個橫向的座標,然後這個文字就會有一個 xMax
和一個 yMax
,xMax
就是文字最尾端的座標位置,而 yMax
就是文字最頂端的位置。
然後文字也有相反的兩個值 xMin
和 yMin
,而這兩個值就是剛好相反,是文字開始的位置和底部的位置。
也可以理解為從底緣的基線到文字的最頂端的距離,這就是
yMax
。而底緣的基線到文字的最底端的距離就是yMin
。而xMin
到xMax
,從原點到文字開始和文字結束的距離。
最後這裡面的 advance
就是整個字佔用的空間。
以上講的就是橫向排版的時候,而縱排又有另外一套的邏輯:
我們需要理解一些文字這樣的基礎概念,然後我們才能更好的理解文字和盒的混排。
我們大致瞭解了這個文字在字型裡面是如何定義之後,我們就可以來講講 CSS 裡面的行模型了。這裡我們重點講 5 條線,其他還有一些線和位置例如 sub
和 sup
這種我們就不去講了。
這個 base-line 和文字的頂原和底緣,分別叫做 base-line
、text-top
和 text-bottom
。就是圖中的一條黃線和兩條綠線。
結合剛剛講到的,base-line
就是用來與英文字母對齊的。然後這裡面有一個 text-top
和一個 text-bottom
,如果我們的字型大小不變,這兩個線是不會變得。
如果我們使用多個文字的字型混排的話,這個 text-top
和 text-bottom
是由 fontSize
最大的一個字型決定的。然後這個文字的上緣和下緣可以理解為兩條固定的線。
如果行高是大於文字的高度的時候,我們就會有 line-top
和 line-bottom
,就是在圖中的兩條白色的線。
好!如果我們只有文字的話,這個行模型就這樣子排布的。但是我們一旦涉及到跟盒的混排,就會涉及到一個 line-top
和 line-bottom
的偏移問題。
當我們的盒足夠大的時候,我們的盒子是從 text-bottom
去對齊的,所以它就有可能把這個高度撐開。這個時候 line-top
就會從虛線的位置,移動到了白色的實線的位置。(看上面的圖)
這個現象也是在正常流當中,處理行模型中非常麻煩的一個現象。因為盒的先後順序和尺寸都是影響
line-top
和line-bottom
的位置。但是盒是不會影響text-top
和text-bottom
的。
接下來我們來一起看看在瀏覽器中的實際效果是怎麼樣,需要在瀏覽器上看效果,我們就需要些一段程式碼了。
wrapper
把我們的內容包裹起來,然後給一個背景顏色span
標籤加入文字div
標籤建立一個元素,然後給予這個元素 display: inline-block
,把元素設定成行內盒
基線
的元素 base-line
,用這個來展示我們的基線是在哪個位置<style>
.wrapper {
margin: 2rem;
font-size: 50px;
line-height: 100px;
background-color: #2d2f42;
}
.base-line {
overflow: visible;
display: inline-block;
width: 1px;
height: 1px;
}
.base-line div {
width: 1000px;
height: 1px;
background: fuchsia;
}
.text {
color: #ddd;
}
.inline-box {
line-height: 70px;
width: 100px;
height: 150px;
background-color: aqua;
display: inline-block;
}
</style>
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box"></div> <!-- 行級盒 -->
</div>
最後呈現出來的效果如下:
這裡我們發現,我們的
行內盒
是預設與基線對齊的規則。也就是說盒的下邊緣會和文字的基線去做對齊。
好,如果我們在盒子裡面加文字又會怎麼樣呢?我們來試試看。
這裡我們在盒裡面加入一個 b
的文字。
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box">b</div> <!-- 行級盒 -->
</div>
最後呈現出來的效果就是這樣的:
這裡我們會發現盒子的對齊的位置發生了變化。盒的基線變成了它裡面文字的最後一行的基線。也就是說,當一個盒子裡面有文字的時候,這個盒子的對齊就會基於裡面文字的基線做對齊。
這裡如果我們在 b
的下一行加一個文字 c
,我們又會發現另一種現象。
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box">b<br/>c</div> <!-- 行級盒 -->
</div>
這個是特別需要注意的問題,行內盒
inline-block
的基線是隨著自己裡面的文字去變化的。所以說大部分情況下是不建議大家給行內盒使用基線對齊的。
所以我們在使用行內盒
的時候就需要給一個 vertical-align
,屬性值我們可以給 top
,bottom
或者是middle
都是可以的。
我們先看看 vertical-align: top
—— 頂緣對齊
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: top">b<br/>c</div> <!-- 行級盒 -->
</div>
給
top
就是跟行的頂緣對齊,因為我們的外包框給的是 100px,所以它會把這一行撐開。
然後我們來看看 vertical-align: bottom
—— 底緣對齊
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: bottom">b<br/>c</div> <!-- 行級盒 -->
</div>
與頂緣對齊不一樣就是這個時候,盒就會從下面往上撐開。
最後我們看看 vertical-align: middle
—— 中線對齊
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: middle">b<br/>c</div> <!-- 行級盒 -->
</div>
顧名思義,這個時候盒就會與文字的中線對齊。
其實這裡我們還可以讓盒與文字的頂緣和底緣對齊,也就是 text-top
和 text-bottom
。
我們來看看 text-bottom
是怎麼樣的:
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: text-bottom">b<br/>c</div> <!-- 行級盒 -->
</div>
盒一樣會把上邊緣和下邊緣撐開。
如果我們看到上面的如,紫色的線就是我們的基線,但是我們也可看看文字的中心線
、頂緣線
和底緣線
的位置。我們只需要改動 base-line
這個 div
元素的 vertical-align
屬性即可:
我們先看看中線:
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line" style="vertical-align: middle"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: text-bottom">b<br/>c</div> <!-- 行級盒 -->
</div>
頂緣線:
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line" style="vertical-align: top"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: text-bottom">b<br/>c</div> <!-- 行級盒 -->
</div>
底緣線:
<div class="wrapper"> <!-- 外包框 -->
<div class="base-line" style="vertical-align: bottom"> <!-- 對齊基線 -->
<div></div>
</div>
<span class="text">Hello world 中文</span> <!-- 文字內容 -->
<div class="inline-box" style="vertical-align: text-bottom">b<br/>c</div> <!-- 行級盒 -->
</div>
這裡我們可以觀察到,我們的盒是把我們的
頂緣線 (top-line)
往上撐開了的,所以也證明我們行內盒是會把頂緣或者下緣撐開的。
為了讓大家可以更加直觀的看到頂緣和底緣被撐開的現象,我們可以加多一個行內盒,同時把頂緣和底緣同時撐開。
<div class="wrapper">
<div class="base-line">
<div></div>
</div>
<span class="text">Hello world 中文</span>
<div class="inline-box" style="vertical-align: text-bottom">
b
<br />
c
</div>
<div class="inline-box" style="vertical-align: text-top">
b
<br />
c
</div>
</div>
這裡我們可以明顯發現,我們外包框的高度已經被撐開了,所以外包框的高度已經不是等於行內盒的高度了,應為它的頂緣和底緣線都被撐開了。這個顯現就是行內盒不同的
align
對齊所導致的,所以不同的vertical-align
對整個行的高度是有比較多的影響的。所以相對於flex
佈局,flex
就只需要去考慮最高的一個元素,但是在正常流裡面的行模型還是比較複雜的。
最後我給大家附上這段程式碼的演示:
接下來我們來一起了解一下,正常流的塊級排布。我們在上一部分已經瞭解了塊級排布了。接下來我們一起來了解行級與塊級的盒之間是如何排布的。
之前講到的 BFC 和 IFC 的基本定義的時候,我們對塊級排布已經有一個基礎的認識了。但是呢正常流當中還有兩個非常複雜的機制,我們需要先了解一下。
Float 和 Clear 也稱為 浮動
與 清除浮動
。首先浮動元素嚴格來說已經脫離了正常流,當時他又依附於正常流去定義的一類排布方式。
首先我們先來講一下 float
的基本規則。根據 W3C 的標準,float 可對它有一下定義:
float 元素可以先排到頁面的某一個特定的位置,同時可以當它是正常流裡的元素。然後如果它的屬性中有
float
的時候,這個元素就會朝著float
屬性定義的方向去擠。
假設元素加入一個 float: left
屬性,這個時候,這個元素就會往左邊去擠,如下圖:
通過上面這個動畫,我們會發現,原來已經存在的文字位置就被浮動了的元素所 「蓋住」 了。所以呢這個時候就會根據 float 所佔據的區域去調整行盒的位置。因為計算位置的時候我們還沒有去計算每一個文字具體的位置,所以說理論上來講這個地方的文字是沒有重排的。
所以當一個元素變成了浮動時,它所佔據的位置的原本內容,就會根據 float 之後佔據的寬度來進行調整。而 float 顯著的特徵就是,它會影響我們生成這些行盒的尺寸。
所以在文字調整了之後我們最終看到瀏覽器呈現的效果是這樣的:
float 不止會影響自己所在的行,凡是它的高度所佔據的範圍內的所有行盒都會根據 float 元素的尺寸調整自己的大小。如果超出了這個 float 範圍的就不考慮了。
如果我們有兩個 float 元素的時候,還會出現一種情況。假設我們現在有兩個 float 元素,一個是 float: right 在右邊,然後再後面又加入了一個 float 元素,而這個新的 float 元素一樣也是向右浮動的。
這個時候我們會發現這個新的 float 元素也會受到上一個 float 元素影響,新的 float 元素是無法佔據上一個 float 元素的位置。這時候的這個現象就是 float 元素相堆疊的效果。
當讓如果我們繼續新增
float
元素,並且也是浮動一樣的方向的時候,都會受到上面多個float
元素的影響並且繼續堆疊。
接下來我們來看看一段範例程式碼:
<style>
.float-box {
float: right;
width: 100px;
height: 100px;
background-color: fuchsia;
color: #ededed;
}
.wrapper {
padding: 1.5rem;
background: #2d2f42;
color: #ededed;
}
.purple {
color: fuchsia;
}
</style>
<div class="wrapper">
<span class="purple">「float-放置的位置」</span>
<div class="float-box"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
<span class="purple">「float-放置的位置」</span>
<div class="float-box"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
<span class="purple">「float-放置的位置」</span>
<div class="float-box"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
<span class="purple">「float-放置的位置」</span>
<div class="float-box"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
</div>
這裡面 「float-放置的位置」
就是原本這個 float 元素的程式碼所放置的位置。但是經過了 float 之後,所有的 float 元素都會被擠到最右邊的位置。最後所有行盒的生成都會圍繞著所有的 float 元素,同時它們都不會佔據 float 元素的空間。
這個時候當我們把外框的寬度增加的時候,就會發現這些 float 元素就會出現堆疊的現象。
看到這裡肯定很多同學說覺得 「這樣排版不行呀,老闆肯定不收貨呀」,「UI 設計師肯定要吊打我們啦」。是的這樣的排版確實是不正常的,而且一般來說也沒有這麼排版的需求呢。
所以這裡我們可以給 float 加一個 clear 屬性,這樣我們就可以讓它們強制換行了。
<style>
.float-box {
float: right;
width: 100px;
height: 100px;
background-color: fuchsia;
color: #ededed;
}
.wrapper {
padding: 1.5rem;
background: #2d2f42;
color: #ededed;
}
.purple {
color: fuchsia;
}
</style>
<div class="wrapper">
<span class="purple">「float-放置的位置」</span>
<div class="float-box"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
<span class="purple">「float-放置的位置」</span>
<div class="float-box" style="clear:right"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
<span class="purple">「float-放置的位置」</span>
<div class="float-box" style="clear:right"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
<span class="purple">「float-放置的位置」</span>
<div class="float-box" style="clear:right"></div>
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
</div>
所謂的 clear
有的翻譯成 「清除浮動」,但是我覺得它不是清除浮動的意思。理論上來說它是 「找一個乾淨的空間來執行浮動」 的意思。
比如說 clear: right
,就是要在右邊找到一個乾淨的空間來執行這個浮動的操作。
所以看到上圖的效果,當我們加入了 clear: right
之後,第一個後面的元素都不受第一個 float 元素的影響,各自找到一個乾淨的空間進行浮動。所以 clear
是有分 left
和 right
,指的是向左或者右找乾淨的空間進行浮動。
雖然說 float
這種浮動佈局給我們帶來了不少的麻煩,但是 float 的堆疊、自動換行(或者使用 clear 去換行)的行為是可以幫助我們去進行一些有用的佈局的。因為我們的正常流的佈局在早年沒有 flex
的情況下,正常流的佈局下完成一些著名的 CSS 佈局需求的時候是非常的困難的。
所以大家都產生這種使用 float 來代替正常流的 inline-block 來進行佈局的技術。
接下來我們看看下一段程式碼範例:
這裡我們給每一個元素都加上一個 float
,這時候元素跟元素之間的表現就很像一個正常流了。因為 float 元素它佔滿了之後還是會換行的。那麼我們來看一下程式碼:
<style>
.float-box {
margin: 10px;
float: left;
width: 100px;
height: 100px;
background-color: fuchsia;
color: #ededed;
text-align: center;
line-height: 100px;
font-size: 50px;
}
</style>
<div class="float-box">1</div>
<div class="float-box">2</div>
<div class="float-box">3</div>
<div class="float-box">4</div>
<div class="float-box">5</div>
<div class="float-box">6</div>
<div class="float-box">7</div>
這裡我們可以看到,float 是完全可以變成和正常流一樣排成一行的,當我們縮小寬度的時候,不夠位置的元素就會自動換到下一行。
[外連圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-UsH8GwbC-1602443824687)(/Users/tridiamond/Library/Application Support/typora-user-images/image-20201006194359630.png)]
這個時候如果我們想執行一個強制換行怎麼辦呢?這個時候我們就可以拿出我們的 clear
。比如說我們想在 3
後面開始強制換行,我們就可以在 4
的浮動元素上加入 clear: left
即可。
這裡要注意的是,float 它是不認
<br/>
的,如果我們在一個 float 元素的後面加入<br>
是無法讓他強制換行的。因為br
是正常流的換行,對 float 是沒有效的。
<style>
.float-box {
margin: 10px;
float: left;
width: 100px;
height: 100px;
background-color: fuchsia;
color: #ededed;
text-align: center;
line-height: 100px;
font-size: 50px;
}
</style>
<div class="float-box">1</div>
<div class="float-box">2</div>
<div class="float-box">3</div>
<div class="float-box" style="clear: left">4</div>
<div class="float-box">5</div>
<div class="float-box">6</div>
<div class="float-box">7</div>
我們平時做佈局的時候,基本上我們都會使用盒而不是文字。我們很少有真正意義上需要像原始的 float 設計一樣用圖文混排的設計(就是向我們看的圖書一樣的佈局方式)。在網頁上佈局,一般來說我們都是針對同一個級別,我們都是幾個盒子排成正確的形狀來完成頁面上的佈局。
所以說 float 這種佈局的技術,在比較早期的時代是非常流行的。不過到了現在的前端技術時代,float 的佈局方式已經完全被 Flexbox
技術所替代了。這裡只是讓大家知道一下,佈局的歷史裡面有這麼一個用法。
如果有同學遇到了一些需要維護非常古老的程式碼,就有可能看到這個技術。但是我不推薦大家當今還去使用這項技術。
接下來我們來講講正常流裡面的一種現象,叫做 margin 摺疊
。在 BFC 裡我們的元素是順次從上往下排的,但是順次從上往下排的時候還是會受它的盒模型影響的。
就是有這麼一個現象,在一個從上往下排布的 BFC 裡面,有一個元素它有 margin,接著還有一個元素,它也有 margin。那麼這個時候第二個元素它應該怎麼排呢?
直接告訴我們應該是兩個元素的 margin
是應該會疊加,如果第一個的 margin 是 10,第二個是 15,那麼兩個元素中間就是 10 + 15 = 25。對吧?不是的。
它們並不是把兩個 margin 的空白都留出來。而是會讓他們兩個發生一個堆疊的這樣的現象。最後疊出來的高度是跟最大的 margin 的高度相等的。如果一個是 10px,一個是 15px 的 margin,最後兩個元素之間的空間就是 15px(使用了兩個 margin 的最大值)。這個現象就是
Margin Collapse (留白摺疊/邊距摺疊)
。
有些同學覺得真的是匪夷所思,根本不符合常理。但是其實這個是一個排版裡面的要求,因為在我們的排版當中,任何一個元素,它的盒模型裡面所謂的 margin 「只是要求周圍有這麼多的空間是留白的,而不會說要求元素與元素之間的邊距格子都有相對應的空白」。所以只要元素的周圍的留白的空間夠了,自然就是一個合理的排版方式。
這個可以說也是繼承了印刷行業,古老的印刷行業的排版體系中,這種 Margin Collapse
是一個非常自然的現象和思路。
我們要注意,這種
Margin Collapse
只會發生在 BFC 裡面。它不會發生在 IFC 或者其他的排版方式裡面,比如說 flex、grid 等都不會有Margin Collapse
的。所以只有正常流中的 BFC 會發生邊距摺疊!
其實我們單看 float和單看邊距摺疊,它們都不太難,我們但看 BFC 也不太難。但是如果我們三個現象疊加在一起,基本上就是我們古代前端最大的難題了。也就是說大家平時會看到一些資料裡面講,面試的時候遇到的 BFC 問題就都在這個三個現象相疊加的。
接下來我們來認識一下正常流最困難的一部分,"BFC 合併
"。在講到具體的知識之前我們先來了解一下幾個概念。
BFC 代表的是
Block Formatting Context (塊級格式化上下文)
。
我們先大致瞭解一下 Block
裡面有哪些:
這裡我們就逐個拆開來講一下:
Block Containter 基本上是一些 display 的效果:
table-row
就不是 block cotainer
了,因為它裡面是 table-cell,所以不可能是正常流display: flex
的元素不是 block container
,但是 flex 的子元素 flex item
如果它們沒有特殊的 display 屬性的話它們都是 block container。任何一個元素裡面只要不是特殊 display 模式的,它裡面預設就是正常流。
我們大多數的元素的 display 的值都是有一對的。一個是 block-level
的,一個是 inline-level
的。
Block level | Inline level |
---|---|
display: block | display: inline-block |
display: flex | display: inline-flex |
display: grid | display: inline-grid |
display: table | Display:inline-table |
在 display 的最新標準裡面,已經把
block-level
和inline-level
拆成了單獨的屬性。Display 會出現這個inner
和outer
,這裡就是給 display 做了系統性的分解。
這裡還有一種非常特殊的 display 屬性叫
run-in
。它跟著自己上一個元素來,有時候是 inline-level,有的時候是 block-level。這個屬性我們知道就可以了,在工作中基本上沒有見過有例子有運用到run-in
這個屬性。
在標準裡面有這麼一個描述:「什麼時候什麼樣的盒,會建立 BFC 呢?」
設立 BFC (Establish BFC)
以下情況下會 設立 BFC
- floats —— 浮動的元素裡面就是一個正常流,所以會建立 BFC
- Abusolutely positioned elements —— 絕對定位的元素裡面也會建立 BFC
- block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes —— 就是這個
block container
但是不是block box
(也就是不是 block-level ) 會建立 BFC,包括以下:
- inline-blocks
- table-cells
- table-captions
- Flex items
- grid cell
- 等等…
- and block boxes with
overflow
other thanvisible
—— 就是擁有overflow
屬性,但是不是visible
的block box
也會建立 BFC
所以設立 BFC 一共有 4 大類,但是要記住這些確實不太好記。不過換一種方式來理解就好記一點了。
預設這些能容納正常流的盒,我們都認為它們會建立 BFC,但是隻有一種情況例外:就是 block box 裡外都是 BFC 並且 overflow 是 visible。用公式來記就是這個:「block box && overflow:visible」
這個其實是非常合理的,它裡外都是 BFC 而且它的 overflow
是 visible
,那不就相當於沒有 BFC 了嗎?所以這個時候會發生 BFC 合併。
那 BFC 合併之後會發生什麼呢?這裡我們就需要了解兩個最重要的 BFC 合併之後的影響:
因為 BFC 發生了合併,所以裡面的行盒跟這個 float就有了一定的影響。
正常的來講我們放一個 block box 它的 overflow 不是 visible,這個時候它會建立 BFC 並且整個 block box 放進 BFC 裡面。那麼整個就會受 BFC 影響,如果不建立 BFC它裡面的行盒就會受 float 的影響。
下來我們用一段程式碼來看看其中的現象:
<style>
.float-box {
float: right;
width: 100px;
height: 100px;
background-color: aqua;
margin: 20px;
}
.text {
background-color: #2d2f42;
color: #ededed;
overflow: visible;
margin: 30px;
}
</style>
<div class="float-box"></div>
<div class="text">
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
</div>
這裡因為我們的
text
盒子給予了overflow: visible
,所以這個overflow
屬性值是不滿足建立 BFC 的條件的。所以我們的文字的盒子就會像不存在一樣,文字就會環繞著外面的float-box
元素來進行排布。
如果我們把 overflow
的屬性值改為 hidden
的話,那麼 text
的盒子就會建立 BFC。
<div class="float-box"></div>
<div class="text" style="overflow: hidden">
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字 文字
</div>
這裡我們就很明顯的可以看見一個變化,
text
的元素整體作為一個 block level 的元素被排進了 BFC 裡面。也就是說這個時候text
元素的寬度整個圍繞著float-box
元素來進行排布了。
剛剛我們講到, BFC 只會發生在同一個 BFC 裡面。如果建立了新的 BFC 的話,它就不會發生邊距摺疊。如果沒有建立 BFC 的話,它就存在著一個同向邊距摺疊。
好,同樣我們用一段程式碼的範例來試驗一下:
<style>
.box {
width: 100px;
height: 100px;
background-color: aqua;
margin: 20px;
}
.overflow-box {
overflow: visible;
background-color: #2d2f42;
}
</style>
<div class="box"></div>
<div class="overflow-box">
<div class="box"></div>
</div>
這裡的兩個
box
元素都給予了 100 x 100px 寬高,同時有一個 20px 的外邊距。第二個box
元素我們用一個含有overflow
屬性的div
包著。首先我們預設給予這個overflow
元素overflow: visible
,然後我們來看看會出現什麼效果。
出來的效果顯而易見,我們可以看到上面和下面的兩個 box
元素的外邊距發生了邊距摺疊
現象。這裡兩個盒子就當做 overflow
這個元素不存在一般,最後他們兩個的距離就是 20px。
這裡做一個小實現,如果我們給 overflow
元素加入一個 margin-top: 30px
,這個時候會對這兩個 box
的距離發生影響嗎?
答案是:會的!但是還是還是會出現
邊距摺疊
的現象,只是它們之間的距離變成了 30px,但是並不會變成 20+30+20 這樣的效果。我們來看看執行效果:
<div class="box"></div>
<div class="overflow-box" style="margin-top: 30px">
<div class="box"></div>
</div>
最後如果我們把 overflow-box
的 overflow
屬性改為 hidden
, 這個時候它就會建立 BFC。這時候我們就會發現,邊距摺疊
現象就會消失,最終兩個 box
元素的距離就是 30+20 = 50px。
<div class="box"></div>
<div class="overflow-box" style="margin-top: 30px; overflow: hidden;">
<div class="box"></div>
</div>
「不知道這裡發生了什麼,但是覺得很棒!哈哈」
這裡的
overflow-box
裡面的box
元素已經和外面的box
元素不在同一個 BFC 裡面了。所以它們之間不會再發生邊距摺疊現象。但是 外面的overflow-box
和box
是處於同一個 BFC 中,所以它們兩個依然會發生邊距摺疊現象。所以這個就是建立 BFC 對邊距摺疊這個行為的影響。
我是來自《技術銀河》的三鑽:「學習是為了成長,成長是為了不退步。堅持才能成功,失敗只是因為沒有堅持。同學們加油哦!下期見!」
小夥伴們可以檢視或者訂閱相關的專欄,從而集中閱讀相關知識的文章哦。
📖 《前端進階》 — 這裡包含的文章學習內容需要我們擁有 1-2 年前端開發經驗後,選擇讓自己升級到高階前端工程師的學習內容(這裡學習的內容是對應阿里 P6 級別的內容)。
📖 《資料結構與演演算法》 — 到了如今,如果想成為一個高階開發工程師或者進入大廠,不論崗位是前端、後端還是AI,演演算法都是重中之重。也無論我們需要進入的公司的崗位是否最後是做演演算法工程師,前提面試就需要考演演算法。
📖 《FCC前端集訓營》 — 根據FreeCodeCamp的學習課程,一起深入淺出學習前端。穩固前端知識,一起在FreeCodeCamp獲得證書
📖 《前端星球》 — 以實戰為線索,深入淺出前端多維度的知識點。內含有多方面的前端知識文章,帶領不懂前端的童鞋一起學習前端,在前端開發路上童鞋一起燃起心中那團火🔥