1.盒模型是CSS的基石之一,它指定元素如何顯示以及(在某種程度上)如何相互交互。頁面上的每個元素被看作是一個矩形框,這個框由元素的內(nèi)容、內(nèi)邊距、邊框和外邊距組成。
內(nèi)邊距出現(xiàn)在內(nèi)容周圍。如果在元素上添加背景,那么背景會應(yīng)用于由內(nèi)容和內(nèi)邊距組成的區(qū)域。添加邊框會在內(nèi)邊距的區(qū)域外邊加一條線。在邊框的外邊是外邊距。外邊距是透明的。一般使用它控制元素之間的間隔。
在CSS中,width和height指的是內(nèi)容區(qū)域的寬度和高度。增加內(nèi)邊距、邊框、外邊距不會影響內(nèi)容區(qū)域的尺寸,但是會增加元素框的總尺寸。假設(shè)框的每個邊上有10像素的外邊距和5像素的內(nèi)邊距,如果希望這個框達(dá)到100像素寬,就需要將內(nèi)容的寬度設(shè)置為70像素。
2.外邊距疊加是一個相當(dāng)簡單的概念。簡單的說,當(dāng)兩個或者更多垂直外邊距相遇時(shí),它們將形成一個外邊距。這個外邊距的高度等于兩個發(fā)生疊加的外邊距的高度中的較大者。
當(dāng)一個元素包含在另一個元素中時(shí)(假設(shè)沒有內(nèi)邊距或者邊框?qū)⑼膺吘喾指糸_),它們的頂或底外邊距也會發(fā)生疊加。盡管看上去有些奇怪,但是外邊距甚至可以與自身發(fā)生疊加。假設(shè)有一個空元素,它有外邊距,但是沒有內(nèi)邊距和邊框。在這種情況下,頂外邊距與底外邊距就碰到了一起,它們會發(fā)生疊加。
只有普通文檔流中塊框的垂直外邊距才會發(fā)生外邊距疊加。行內(nèi)框、浮動框或絕對定位框之間的外邊距不會疊加。
3.CSS中有3種基本的定位機(jī)制:普通流、浮動和絕對定位。顧名思義,普通流中元素框的位置由元素在HTML中的位置決定。
塊級框從上到下一個接一個地垂直排列,框之間的垂直距離由框的垂直編劇計(jì)算出來。
行內(nèi)框在一行中水平排列??梢允褂盟絻?nèi)邊距、邊框和外邊距調(diào)整它們的水平間距。但是垂直內(nèi)邊距、邊框、外邊距不影響行內(nèi)框的高度。同樣在行內(nèi)框設(shè)置顯式的高度和寬度也沒有影響。但是設(shè)置行高可以增加這個框的高度。
4.CSS的position屬性設(shè)置元素的定位方式,為將要定位的元素定義定位規(guī)則。該屬性在將動畫特效腳本化時(shí)尤其有用。初始值為static。
定位元素是計(jì)算后位置屬性為relative、absolute、fixed或sticky的元素。
相對定位元素是計(jì)算后位置屬性為relative的元素 。
絕對定位元素是計(jì)算后位置屬性為absolute或fixed的元素。
粘性定位元素是計(jì)算后位置屬性為sticky的元素。
static
該關(guān)鍵字指定元素使用正常的布局行為,即元素在文檔流中當(dāng)前的布局位置。此時(shí) top, right, bottom, left 和 z-index 屬性無效。
relative
該關(guān)鍵字下,元素先放置在未添加定位時(shí)的位置,再在不改變頁面布局的前提下調(diào)整元素位置(因此會在此元素未添加定位時(shí)所在位置留下空白)。position:relative 未定義對 table-*-group, table-row, table-column, table-cell, table-caption 元素應(yīng)用的效果。
absolute
不為元素預(yù)留空間,通過指定元素相對于最近的非 static 定位祖先元素的偏移,來確定元素位置。絕對定位的元素可以設(shè)置外邊距(margins),且不會與其他邊距合并。
fixed
不為元素預(yù)留空間,而是通過指定元素相對于屏幕視口(viewport)的位置來指定元素位置。元素的位置在屏幕滾動時(shí)不會改變。打印時(shí),元素會出現(xiàn)在的每頁的固定位置。fixed 屬性會創(chuàng)建新的棧上下文。當(dāng)元素祖先的 transform 屬性非 none 時(shí),容器由視口改為該祖先。
sticky
元素先按照普通文檔流定位,然后相對于該元素在流中的 flow root(BFC)和 containing block(最近的塊級祖先元素)定位。在所有情況下(即便被定位元素為 table 時(shí)),該元素定位均不對后續(xù)元素造成影響。當(dāng)元素 B 被粘性定位時(shí),后續(xù)元素的位置仍按照 B 未定位時(shí)的位置來確定。position: sticky 對 table 元素的效果與 position: relative 相同。
5.相對定位是一個非常容易掌握的概念。如果對一個元素進(jìn)行相對定位,它將出現(xiàn)在它所在的位置上。然后可以通過設(shè)置垂直或者水平的位置,讓這個元素“相對于”它的起點(diǎn)移動。如果將top設(shè)置為20像素,那么框?qū)⒊霈F(xiàn)在原位置頂部下面20像素的地方。如果將left設(shè)置為20像素,那么會在元素左邊創(chuàng)建20像素的空間,也就是將元素向右移動。在使用相對定位的時(shí),無論是否移動元素仍然占據(jù)原來的空間。因此,移動元素會導(dǎo)致它覆蓋其他框。
6.相對定位元素并未脫離文檔流,而絕對定位元素則脫離了文檔流。在布置文檔流中其他元素時(shí),絕對定位元素不占據(jù)空間。絕對定位元素相對于最近的非static定位的祖先元素定位。當(dāng)這樣的祖先元素不存在時(shí),則相對于根級容器定位。
7.固定定位與絕對定位相似,但元素的包含塊為viewport視口。該定位方式常見于創(chuàng)建在滾動屏幕時(shí)仍固定在相同位置的元素。
8.粘性定位是相對定位和固定定位的混合。元素在跨越閾值之前為相對定位,之后為固定定位。
9.CSS中float屬性可以使一個元素脫離正常的文檔流,然后被安放到它所在的容器的左端或者右端,并且其他文本和行內(nèi)元素環(huán)繞著它。浮動元素指那些float屬性不為none的元素。
left
表明元素必須浮動在其所在的塊容器左側(cè)的關(guān)鍵字。
right
表明元素必須浮動在其所在的塊容器右側(cè)的關(guān)鍵字。
none
表明元素不進(jìn)行浮動的關(guān)鍵字。
inline-start
關(guān)鍵字,表明元素必須浮動在其所在塊容器的開始一側(cè),在ltr腳本中是左側(cè),在rtl腳本中是右側(cè)。
inline-end
關(guān)鍵字,表明元素必須浮動在其所在塊容器的結(jié)束一側(cè),在ltr腳本中是右側(cè),在rtl腳本中是左側(cè)。
10.清除浮動可以對想要清除浮動的元素使用clear屬性,但是這個方法只是在同一塊級格式化上下文中沒有其他浮動元素時(shí)才是有效的。如果不能使用清除浮動,另一種做法是浮動容器的限制塊級格式化上下文。
11.塊級格式化上下文
CSS > 譯文:理解CSS中的塊級格式化上下文
塊級格式化上下文(Block Formatting Context)是網(wǎng)頁CSS視覺渲染的一部分,并用于決定塊盒子的布局。在定位體系(Positioning Scheme)中它屬于常規(guī)流(Normal Flow)。根據(jù)W3C所言:
浮動、絕對定位元素(position為 absolute或 fixed)、行內(nèi)塊元素 display:inline-block、表格單元格display:table-cell、表格題 display:table-caption 以及 overflow 屬性值不為 visible 的元素(除了該值被傳播到視點(diǎn) viewport 的情況)將創(chuàng)建一個新的塊級格式化上下文。
上面的引言差不多總結(jié)了一個BFC是如何形成的。但讓咱們用另外一種更通俗易懂的方式來重定義它。一個BFC就是一個HTML盒子,它至少滿足以下條件之一:
float 的值不為 none
position 的值不為 static 或 relative
display 的值為 table-cell、table-caption、inline-block、flex 或 inline-flex
overflow 的值不為 visiable
創(chuàng)建一個塊級格式化上下文
一個BFC可以顯式觸發(fā)。如果我們想創(chuàng)建之,我們只需給它添加上面提到的任何一個CSS樣式。
比如,看下面的HTML:
<div class="container">
Some Content here
</div>
一個新的BFC可以通過給容器添加任意一個必要的CSS樣式來創(chuàng)建,比如overflow: scroll,overflow: hidden,display: flex,float: left,或 display: table 。盡管上述條件都可以創(chuàng)建BFC,但也會產(chǎn)生一些其他效果,如:
display: table 可能引發(fā)響應(yīng)性問題
overflow: scroll 可能產(chǎn)生多余的滾動條
float: left 將把元素移至左側(cè),并被其他元素環(huán)繞
overflow: hidden 將裁切溢出元素
所以無論何時(shí),當(dāng)要創(chuàng)建一個BFC時(shí),我們要基于需求選擇最恰當(dāng)?shù)臉邮?。為了保持一致性,我在本文的所有例子中均使用overflow: hidden。
.container { overflow: hidden;}
你可以自由選擇使用除 overflow: hidden 之外的其他樣式。
BFC中盒子的對齊
W3C規(guī)范道:
在BFC上下文中,每個盒子的左外側(cè)緊貼包含塊的左側(cè)(從右到左的格式里,則為盒子右外側(cè)緊貼包含塊右側(cè)),甚至有浮動也是如此(盡管盒子里的行盒子 Line Box 可能由于浮動而變窄),除非盒子創(chuàng)建了一個新的BFC(在這種情況下盒子本身可能由于浮動而變窄)。
簡單來說,如上圖所示,所以屬于BFC的盒子都左對齊(在從左到右的格式下)并且它們的左外側(cè)緊貼包含塊的左側(cè)。在最后一個盒子中我們可以看到盡管左側(cè)存在一個浮動元素(棕色),另外一個元素(綠色)仍然緊貼包含塊的左側(cè)。該情況的產(chǎn)生原理將在下文關(guān)于文字環(huán)繞的部分中討論。
BFC造成的外邊距折疊
在常規(guī)流中,盒子從包含塊的頂部開始一個個地垂直擺放。兩個同胞盒子間的垂直舉例由兩個盒子各自的外邊距所決定,但不是二者外邊距之和。
為便于理解,我們看個例子。
在上圖中,一個紅盒子(div)包含著兩個同胞綠元素(p),一個BFC已經(jīng)創(chuàng)建了出來。
<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
</div>
相應(yīng)的CSS是:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}
理論上兩個同胞元素間的外邊距應(yīng)當(dāng)是二者外邊距之和(20px)但實(shí)際上卻是10px。這就是眾所周知的外邊距折疊(Collapsing Margins)。如果同胞元素外邊距不同,將應(yīng)用最大的那個。
使用BFC避免外邊距折疊
在討論了上面BFC折疊外邊距的情況后,現(xiàn)在說避免折疊可能有點(diǎn)讓人摸不著頭腦。但我們必須牢記于心的一件事是,相鄰塊級盒子(同胞)之間的垂直外邊距只有在它們處于同一個BFC時(shí)才會發(fā)生折疊。如果它們分屬于不同的BFC,就不會折疊了。所以,通過創(chuàng)建新的BFC我們可以避免外邊距折疊。
讓我們在早前的例子中添加第三個同胞元素,現(xiàn)在HTML是:
<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
<p>Sibling 3</p>
</div>
CSS是:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}
結(jié)果和上面一樣,即是說,折疊還是會發(fā)生并且三個同胞間分隔的垂直距離是10px。這是因?yàn)槿齻€ p
標(biāo)簽都從屬于同一個BFC。
現(xiàn)在我們修改第三個同胞元素,使之成為一個新的BFC的一部分?,F(xiàn)在的HTML變成了:
<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
<div class="newBFC">
<p>Sibling 3</p>
</div>
</div>
CSS:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
margin: 10px 0;
background-color: lightgreen;
}
.newBFC {
overflow: hidden; /* creates new block formatting context */
}
現(xiàn)在輸出的結(jié)果就有所不同了:
因?yàn)榈诙€和第三個同胞元素現(xiàn)在分屬于不同的BFC,它們之間就不會發(fā)生外邊距折疊了。
使用BFC包含浮動
BFC可以包含浮動。我們經(jīng)常遇到容器中含有浮動元素的情況。這種情況下容器元素沒有高度并且其浮動子元素脫離了網(wǎng)頁的常規(guī)流。我們通常用清除浮動解決這個問題,最普遍的做法就是使用偽元素。但我們也可以通過創(chuàng)建一個BFC來解決問題。
看個例子:
<div class="container">
<div>Sibling</div>
<div>Sibling</div>
</div>
CSS:
.container {
background-color: green;
}
.container div {
float: left;
background-color: lightgreen;
margin: 10px;
}
在上面這個例子中,容器沒有任何高度,并且它包不住浮動子元素。為解決此問題,我們通過添加 overflow: hidden
來在容器中創(chuàng)建一個新的BFC。修改后的CSS成了:
.container {
overflow: hidden; /* creates block formatting context */
background-color: green;
}
.container div {
float: left;
background-color: lightgreen;
margin: 10px;
}
現(xiàn)在容器可以包住浮動子元素,并且其高度會擴(kuò)展至包住其子元素,在這個新的BFC中浮動元素又回歸到頁面的常規(guī)流之中了。
使用BFC避免文字環(huán)繞
有時(shí)候浮動DIV旁邊的文本會環(huán)繞它(如下圖1所示)而這種情況有時(shí)候并不如我們所愿,我們想要下圖2的效果。要解決這個問題,我們可以用外邊距,但也可以用BFC。
首先讓我們弄明白為何文字會環(huán)繞。要理解這個我們必須明白,當(dāng)存在元素浮動的時(shí)候,盒模型如何工作。這就是我早先討論BFC中對齊時(shí)候的遺留問題。我們通過下圖來看圖1到底發(fā)生了什么。

假設(shè)HTML是:
<div class="container">
<div class="floated">
Floated div
</div>
<p> Quae hic ut ab perferendis sit quod architecto, dolor debitis
quam rem provident aspernatur tempora expedita.
</p>
</div>
上圖整個黑色區(qū)域表示 p元素,如我們所見,p元素沒有移位但它疊在了浮動元素之下,而p元素的行盒子(即文本行)卻移位了,行盒子水平變窄來給浮動元素騰出了空間。
隨著文本的增加,最后文本將環(huán)繞在浮動元素之下,因?yàn)槟菚r(shí)候行盒子不再需要移位,也就成了圖1的樣子。這就是為什么即便有浮動元素,段落仍緊貼包含塊的左側(cè),而行盒子會變窄來給浮動元素騰位子。
如果我們能位移整個 p元素,這個環(huán)繞問題也就迎刃而解了。
在說解決方案之前,我們再回顧下W3C規(guī)范:
在BFC上下文中,每個盒子的左外側(cè)緊貼包含塊的左側(cè)(從右到左
格式里,則為盒子右外側(cè)緊貼包含塊右側(cè)),甚至有浮動也是如此
(盡管盒子里的行盒子 Line Box可能由于浮動而變窄),除非盒
子創(chuàng)建了一個新的BFC(在這種情況下盒子本身可能由于浮動而變窄)。
據(jù)此,如果 p 元素創(chuàng)建一個新的BFC那它就不會再緊貼包含塊的左側(cè)了。給 p 元素添加 overflow: hidden 就能輕而易舉地辦到。這解決了文本環(huán)繞浮動對象的問題。
在多列布局中使用BFC
如果我們創(chuàng)建一個占滿整個容器寬度的多列布局,在某些瀏覽器中最后一列有時(shí)候會掉到下一行。這可能是因?yàn)闉g覽器四舍五入了列寬從而所有列的總寬度會超出容器。但如果我們在多列布局中的最后一列里創(chuàng)建一個新的BFC,它將總是占據(jù)其他列先占位完畢后剩下的空間。
我們來舉個三列布局的例子:
這是HTML:
<div class="container">
<div class="column">column 1</div>
<div class="column">column 2</div>
<div class="column">column 3</div>
</div>
CSS:
.column {
width: 31.33%;
background-color: green;
float: left; margin: 0 1%;
}/* Establishing a new block formatting context in the last column */
.column:last-child {
float: none;
overflow: hidden;
}
現(xiàn)在盡管盒子的寬度稍有改變,但布局不會打破。當(dāng)然,對多列布局來說這不一定是個好辦法,但能避免最后一列下掉。這個問題上彈性盒或許是個更好的解決方案,但這個辦法可以用來說明元素在這些環(huán)境下的行為。