從CSS盒子模型說起

前言

總括: 對于盒子模型,BFC,IFC和外邊距合并等概念和問題的總結(jié)

為學(xué)之道,莫先于窮理;窮理之要,必先于讀書。

正文

? CSS盒子模型是CSS基礎(chǔ)中的基礎(chǔ),個(gè)人之前對于這塊的理解有偏差??,由于涉及知識點(diǎn)比較多所以寫一篇總結(jié)備忘。
之前打算的是兩周一次更新博文的,但是時(shí)間用在了刷題上,做了很多l(xiāng)eetcode上算法數(shù)據(jù)結(jié)構(gòu)的題記錄在github,但其實(shí)也有在更新啦~只不過是對之前的一些博文進(jìn)行糾正:)??

? 最近秋招在即,壓力倍增,前幾天把博客導(dǎo)入頁的在讀大三本科生改為了在讀大四本科生,不禁心生感慨,時(shí)光荏苒。轉(zhuǎn)眼間我的這個(gè)小窩竟然已經(jīng)快一年了。當(dāng)初建立這個(gè)站點(diǎn)也是想找個(gè)說話的地方,有的人可能就是不喜歡說,只喜歡寫(比如我),然而自從實(shí)習(xí)后確實(shí)提不起精神來寫了,一是沒精力,二是對于遇到的一些坑不想單獨(dú)寫一篇博客記錄。這里還是想保持一份純凈,就是以總結(jié)和理解難點(diǎn)為主調(diào) 其它的一般會托管在github庫里記錄一下。閑話不多說,說說今天的主角???♀?

? CSS盒子模型想來都不陌生,但還是想先介紹一下,以保證文章的完整性。??

盒子模型

? CSS盒子模型:

盒子模型
盒子模型

在一個(gè)文檔中,每一個(gè)元素都被抽象成一個(gè)盒子,每一個(gè)盒子又包括四部分(從內(nèi)到外):內(nèi)容(content),內(nèi)填充(padding),邊框(border),外邊距(margin)。見上圖,這是從二維的角度分析,來張三維立體圖:??

網(wǎng)上找的圖片

此圖很形象的解釋了CSS盒子的構(gòu)成:

  1. content box:立體盒子的核心
  2. padding box:內(nèi)邊距區(qū)域padding area 延伸到包圍padding的邊框。如果內(nèi)容區(qū)域content area設(shè)置了背景、顏色或者圖片,這些樣式將會延伸到padding上(當(dāng)然我們可以通過background-clip設(shè)置作用區(qū)域)
  3. border box:由border和4條border edge組成。若border寬度設(shè)置為0,則border edge與padding edage重疊;
  4. margin box:由margin和4條margin edge組成。若margin寬度設(shè)置為0,則margin edge與border edage重疊。

??看起來很復(fù)雜的樣子...

拿PS圖層的概念更好理解這塊,最上面的就是content box往下一次是padding box,border box,margin box。

那么盒子模型一般分為兩種:

IE盒子模型

所謂IE盒子模型,就是之前IE瀏覽器實(shí)現(xiàn)的一種怪異的盒子模型,怎么怪異呢?當(dāng)我們這樣設(shè)置的時(shí)候:

div {
    width: 100px;
    height: 100px;
}

理論上我們想要設(shè)置的就是content box的寬高嘛,但是IE在解析的時(shí)候會按照這個(gè)規(guī)則解析:

width = content-width + padding-width + border-width
height = content-height + padding-height + border-height

這就導(dǎo)致了這種尷尬的境地:下面無內(nèi)容的話直接戳這里??

<script async src="https://jsfiddle.net/Damonare/f7vh400t/embed/html,css,result//"></script>

標(biāo)準(zhǔn)盒子模型

標(biāo)準(zhǔn)就比較符合常人的思維了,設(shè)置的width,height就是content的width和height

規(guī)則就是:

width = content-width

height = content-height

實(shí)例如下:無內(nèi)容戳這??

<script async src="https://jsfiddle.net/Damonare/a6oogyyz/embed/html,css,result/"></script>

可能秉著寬大為懷的準(zhǔn)則,CSS3加了個(gè)box-sizing屬性,變相承認(rèn)了這兩種盒子都對(好吧,可能一個(gè)人有一個(gè)人的看法吧),不過box-sizing默認(rèn)屬性就是content-box,即標(biāo)準(zhǔn)盒子模式,IE盒子模型呢,是屬性border-box。剛剛查MDN發(fā)現(xiàn)還有一個(gè)屬性padding-box(width=content-width+padding-width),不過并沒有瀏覽器實(shí)現(xiàn)它(真可憐),并無卵用??

行內(nèi)元素的思考

剛剛說的是以塊級元素為例說的,那么行內(nèi)元素呢?好吧,其實(shí)你知道,行內(nèi)盒是沒法設(shè)置width和height的,那么之前我就有了這樣的思維定勢:行內(nèi)盒沒有padding,margin,然后發(fā)現(xiàn),哦!行內(nèi)盒是有padding-left,padding-right,margin-left,margin-right的!WOC!,然后又發(fā)現(xiàn),行內(nèi)盒是實(shí)際上身懷八甲...??

以下無內(nèi)容戳這里

<script async src="https://jsfiddle.net/Damonare/826gyrrh/embed/html,css,result/"></script>

行內(nèi)盒子的高由font-size決定的;
行內(nèi)盒子的寬等于其子行級盒子的外寬度(margin+border+padding+content width)之和。

是有padding-top和padding-bottom,margin-left,margin-bottom的但并不占據(jù)空間…這就符合盒子模型了嘛,既都是盒子,自然應(yīng)該是一樣的。行內(nèi)盒的margin-top, margin-bottom不占空間,由此聯(lián)想到了另一個(gè)問題——??

外邊距合并

所謂外邊距合并呢,就是margin合并嘛,看下MDN的定義:

塊的頂部外邊距和底部外邊距有時(shí)被組合(折疊)為單個(gè)外邊距,其大小是組合到其中的最大外邊距,這種行為稱為外邊距合并

??注意只是上下,沒有說左右。而且是針對塊級元素說的。

外邊距合并有這幾種情況:

相鄰兄弟元素

//HTML
<div class="up">我在上面</div>
<div class="down">我在下面</div>
//CSS
.up {
  width: 100px;
  height: 100px;
  border: 1px solid blue;
  margin: 100px;
}
.down {
  width: 100px;
  height: 100px;
  border: 1px solid red;
  margin: 100px;
}

我們感性上覺得上下兩個(gè)元素應(yīng)該是相差200px距離,然而并不是。

父子元素

如果塊級父元素中,不存在上邊框、上內(nèi)補(bǔ)、inline content、清除浮動這四條屬性(對于上邊框和上內(nèi)補(bǔ),也可以說,當(dāng)上邊距及上內(nèi)補(bǔ)寬度為0時(shí)),那么這個(gè)塊級元素和其第一個(gè)子元素的上邊距就可以說”挨到了一起“。此時(shí)這個(gè)塊級父元素和其第一個(gè)子元素就會發(fā)生 上外邊距合并 現(xiàn)象,換句話說,此時(shí)這個(gè)父元素對外展現(xiàn)出來的外邊距將直接變成這個(gè)父元素和其第一個(gè)子元素的margin-top的較大者。??

//HTML
<div class="parent">
  <div class="child">我是兒子</div>
</div>
//CSS
.parent {
  width: 100px;
  height: 200px;
  background: red;
  margin-left: 100px;
}
.child {
  width: 50px;
  height: 50px;
  margin-top: 100px;
  border: 1px solid blue;
}

上面代碼感性上可能會覺得,父元素沒有上邊距,然而并不是。

MDN給了三種情況,但第三種空塊元素,我覺得可以包含在這兩種之內(nèi),就沒舉??

那么這種外邊距合并的情況咋解決呢?看下一個(gè)概念...

BFC

??定義:

一個(gè)塊格式化上下文(block formatting context) 是Web頁面的可視化CSS渲染的一部分。它是塊盒子的布局發(fā)生,浮動互相交互的區(qū)域。

那么觸發(fā)BFC的情況有哪些呢?

看MDN:

??一個(gè)塊格式化上下文由以下之一創(chuàng)建:

  • 根元素或其它包含它的元素
  • 浮動 (元素的float 不是 none)
  • 絕對定位的元素 (元素具有 positionabsolutefixed)
  • 內(nèi)聯(lián)塊 inline-blocks (元素具有 display: inline-block)
  • 表格單元格 (元素具有 display: table-cell,HTML表格單元格默認(rèn)屬性)
  • 表格標(biāo)題 (元素具有 display: table-caption, HTML表格標(biāo)題默認(rèn)屬性)
  • 塊元素具有overflow ,且值不是 visible
  • display: flow-root

注意,根元素就創(chuàng)建了一個(gè)BFC

那么BFC又有一下特性:

  1. 內(nèi)部塊級盒子垂直方向排列
  2. 盒子垂直距離由margin決定,同一個(gè)BFC的盒子外邊距會合并
  3. BFC就是一個(gè)隔離的容器,內(nèi)部子元素不會影響到外部元素
  4. 每個(gè)元素的margin box的左邊, 與包含塊border box的左邊相接觸(對于從左往右的格式化,否則相反)。即使存在浮動也是如此。
  5. BFC的區(qū)域不會與float box疊加。

好,上面外邊距合并的兩種情況,利用BFC如何解決呢?下面沒內(nèi)容的話請戳這里??

<script async src="https://jsfiddle.net/Damonare/ejntapom/embed/html,css,result/"></script>

關(guān)于第四五條特性,請看上面的示例。

BFC用途:

  1. 清除浮動;
  2. 解決外邊距合并;
  3. 布局;

塊級盒子的概念

關(guān)于這塊有好多個(gè)概念...首先是塊級元素和塊級盒子:每個(gè)塊級元素至少生成一個(gè)塊級盒,稱為主要塊級盒。一些元素,比如li,生成額外的盒來放置項(xiàng)目符號,不過多數(shù)元素只生成一個(gè)主要塊級盒。

主要塊級盒將包含后代元素生成的盒以及生成的內(nèi)容。它也是可以使用(定位方案 positioning scheme)的盒。

塊容器盒(block container box) 只包含其它塊級盒,或生成一個(gè)行內(nèi)格式化上下文(inline formatting context)

注意塊級盒與塊容器盒概念不同。 前者描述元素跟它的父元素與兄弟元素之間的表現(xiàn),后者描述元素跟它的后代之間的影響。

同時(shí)是塊容器盒的塊級盒稱為塊盒(block boxes)。(注意塊盒和塊級盒并不是全等)

還有一個(gè)特殊的塊盒——匿名塊盒

<div>Some inline text <p>followed by a paragraph</p> followed by more inline text.</div>
//將創(chuàng)建兩個(gè)匿名塊盒,一個(gè)包含 <p> 前面的文本 (Some inline text), 一個(gè)包含 <p> 后面的文本(followed by more inline text), 

塊級元素觸發(fā)BFC,行內(nèi)元素會觸發(fā)啥么?

IFC

IFC 只有在一個(gè)塊級元素中僅包含內(nèi)聯(lián)級別元素時(shí)才會生成。

行內(nèi)盒子的概念

當(dāng)元素的 CSS 屬性 display的計(jì)算值為 inline, inline-blockinline-table時(shí),稱它為行內(nèi)級元素。視覺上它將內(nèi)容與其它行內(nèi)級元素排列為多行。典型的如段落內(nèi)容,有文本(可以有多種格式譬如著重),或圖片,都是行內(nèi)級元素。

行內(nèi)級元素生成行內(nèi)級盒(inline-level boxes),參與行內(nèi)格式化上下文(inline formatting context)。同時(shí)參與生成行內(nèi)格式化上下文的行內(nèi)級盒稱為行內(nèi)盒(Inline boxes)。所有display:inline 的非替換元素生成的盒是行內(nèi)盒。而不參與生成行內(nèi)格式化上下文的行內(nèi)級盒稱為原子行內(nèi)級盒(*atomic inline-level boxes)。這些盒由可替換行內(nèi)元素,或 display 值為 inline-blockinline-table的元素生成,不能拆分成多個(gè)盒。

另外CSS3還新增了兩種格式上下文:GFC(Grid Formatting Contexts)柵格格式化上下文和FFC(Flex Formatting Contexts)Flex格式化上下文,即分別在元素display為grid和flex、 inline-flex 時(shí)觸發(fā)

定位

常規(guī)流

分清了這些盒子的概念,具體怎么排列呢?以下來自MDN:

在常規(guī)流中,盒一個(gè)接著一個(gè)排列。在塊級格式化上下文里面, 它們豎著排列;在行內(nèi)格式化上下文里面, 它們橫著排列。 當(dāng) position為 staticrelative,并且 float 為 none 時(shí)會觸發(fā)常規(guī)流。

浮動(Floats)

對于浮動定位方案(float positioning scheme), 盒稱為浮動盒(floating boxes)。它位于當(dāng)前行的開頭或末尾。這導(dǎo)致常規(guī)流環(huán)繞在它的周邊,除非設(shè)置 clear 屬性。

要使用浮動定位方案,元素 CSS 屬性position 為 staticrelative,然后float不為none 。如果 float設(shè)為 left, 浮動由行盒的開頭開始定位。如果設(shè)為 right, 浮動定位在行盒的末尾。

絕對定位(Absolute positioning)

對于絕對定位方案, 盒從常規(guī)流中被移除,不影響常規(guī)流的布局。 它的定位相對于它的包含塊,相關(guān)CSS屬性:top, bottom, left及right 。

如果元素的屬性position為 absolutefixed, 它是絕對定位元素。

固定定位元素(fixed positioned element)也是絕對定位元素,它的包含塊是視口。當(dāng)頁面滾動時(shí)它固定在屏幕上,因?yàn)橐暱跊]有移動。

以上。

后記

參考文章

外邊距塌陷

Box model

Block formatting context

視覺格式化模型

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,796評論 1 92
  • 引言 這次給大家?guī)砹薈SS-盒子模型部分的筆記,大家一同交流?? 認(rèn)識盒子模型之前,先來了解一下CSS元素的分類吧...
    zhaolion閱讀 4,331評論 9 85
  • ?前端面試題匯總 一、HTML和CSS 21 你做的頁面在哪些流覽器測試過?這些瀏覽器的內(nèi)核分別是什么? ...
    Simon_s閱讀 2,228評論 0 8
  • CSS假定每個(gè)元素都會生成一個(gè)或者多個(gè)矩形框,這稱為元素框(規(guī)范的將來版本可能允許非矩形框,不過對現(xiàn)在來說,框都是...
    四光年閱讀 850評論 0 10
  • 1.CSS基本概念 1.1 CSS的定義 CSS(Cascading Style Sheets)層疊樣式表,主要用...
    寥寥十一閱讀 1,868評論 0 6