一文帶你弄懂 CSS 布局知識
大家好,我是樹哥。
最近想著學(xué)習(xí)點(diǎn)前端知識,于是就學(xué)習(xí)了關(guān)于前端 Web 的布局知識,其實(shí)就是 CSS 那些事。關(guān)于 CSS 其實(shí)很早就接觸過了,但一直沒有沉下心來去學(xué)習(xí),所以對于 CSS 布局的東西一直都不成體系。這次趁著重學(xué)前端,真正花時(shí)間學(xué)了一下 CSS 布局的知識點(diǎn),順帶把知識點(diǎn)總結(jié)一下。
前言
說到 CSS 布局,有寫過一些 CSS 頁面的同學(xué)腦海中可能會浮現(xiàn)一些字眼,例如:float、display、relative、absolute 等等。但這些屬性分別代表什么意思,它們之間都有什么區(qū)別,啥時(shí)候用 float 啥時(shí)候用 relative,你弄得懂嗎?對于我來說,我沒弄懂,有點(diǎn)懵。于是,我花了點(diǎn)時(shí)間弄懂它,這也是本文要重點(diǎn)弄懂的問題。簡單來說,看完這篇文章,你應(yīng)該可以弄清楚如下幾個(gè)問題:
1、常用的幾個(gè) CSS 布局屬性作用及區(qū)別。
2、CSS 布局的歷史以及當(dāng)前流行的布局方式。
要注意的是,本文不會從零開始介紹 CSS 的知識點(diǎn)。只適合學(xué)習(xí)過 CSS,但是對 CSS 布局各種屬性沒弄明白的同學(xué)。如果你還沒學(xué)過 CSS 知識,那需要先去學(xué)習(xí)一下 CSS 基礎(chǔ)知識再來看這篇文章。
關(guān)于文檔流
理解文檔流對于我們掌握 CSS 布局非常重要。簡單來說,我們在 HTML 中寫入的每一個(gè)元素,都是一個(gè)元素塊。默認(rèn)情況下,它們按照我們在 HTML 中書寫的順序,從上到下、從左到右排列,這就是默認(rèn)的文檔流。例如,對于如下所示的代碼片段,其在 HTML 中會按照順序顯示,如下圖所示。
<body>
<p>段落1</p>
<p>段落2</p>
<p>段落3</p>
</body>
核心 CSS 屬性
在 CSS 布局中,有三個(gè)常用的 CSS 屬性,分別是:display、float、position。它們具有不同的功能,適用于不同的場景。
display
就像 display 的名字一樣,其用來定義元素塊的展示形式,不同的展示形式會有不同的展示效果。 display 屬性的常用屬性有:
- inline:表示元素是行內(nèi)元素,多個(gè)元素會共用一行。
- inline-block:表示元素是行內(nèi)塊元素,多個(gè)元素會共用一行。與 inline 的區(qū)別是,inline-block 元素可以設(shè)置元素的長和寬,但是 inline 元素不可以設(shè)置元素的長和寬。
- block:表示元素是塊元素,每個(gè)塊元素會單獨(dú)占用一行。
要注意的是,不同的 HTML 元素,其默認(rèn)的展示形式是不同的。例如 p 元素(段落)的 display 屬性默認(rèn)值是 block,而 a 屬性(鏈接)的 display 屬性默認(rèn)值則是 inine。
下面,我們通過幾個(gè)簡單的例子來體會一下上面所說的內(nèi)容。如下圖所示的代碼,我們設(shè)置不同的 CSS 屬性,元素的展示形式會發(fā)生變化。
<body>
<p class="display">段落1</p>
<p class="display">段落2</p>
<p class="display">段落3</p>
</body>
設(shè)置的 CSS 屬性如下所示:
.display {
background-color: red;
}
顯示效果如下圖所示。
-w524
如上圖可以看到,在 CSS 代碼中,我只是設(shè)置背景顏色。由于 p 元素的默認(rèn) display 屬性值是 block,因此每個(gè)段落都會占用一行的空間。
如果我們把 p 元素設(shè)置成 inline 顯示形式,那么它們就會多個(gè)元素排列在一行內(nèi)。如下圖所示。
.display {
display: inline;
background-color: red;
/* width/height 屬性設(shè)置無效 */
width: 200px;
height: 200px;
}
-w228
如果我們把 p 元素設(shè)置成 inline-block 顯示形式,并且設(shè)置了寬高,那么它們就會多個(gè)元素排列在一行內(nèi),并且寬高設(shè)置會生效。如下圖所示。
.display {
display: inline-block;
background-color: red;
/* width/height 屬性設(shè)置無效 */
width: 200px;
height: 200px;
}
-w639
看到這里,相信大家應(yīng)該可以弄清楚 display 屬性的作用了。display 屬性其實(shí)就是用來設(shè)置 HTML 元素的展示形式的,不同的展示形式會有不同的展示效果。給不同的元素設(shè)置合適的屬性值,可以幫助我們更好地進(jìn)行頁布局。
display 屬性除了前面說得這三種屬性值之外,還有 flex、grid、table 等值。但目前用得最多的還是 flex 和 grid 這兩種,它們可以說是目前主流的 CSS 布局方式。關(guān)于這塊內(nèi)容,我們后面再細(xì)講,這里就不展開了。
float
就像 float 這個(gè)名字一樣,它代表著浮動(dòng)。
啥意思呢?
要理解這個(gè),就要從 CSS 的歷史說起了。很早之前,display 屬性只有兩個(gè),分別是 block 和 inline。block 雖然支持設(shè)置寬高,但是不支持多個(gè)元素顯示在一行。inline 雖然支持多個(gè)元素顯示在一行,但是卻不能設(shè)置寬高。但是實(shí)際場景中,我們很多時(shí)候需要做多列布局的,即需要多個(gè)元素在同一行,并且同一行的元素都可以設(shè)置寬度,如下圖所示。
-w1173
這時(shí)候 CSS 就滿足不了我們的訴求了!
那怎么辦呢?
這時(shí)候 float 就橫空出世了!
簡單來說,float 就是讓塊級元素(block元素)浮起來。 塊級元素浮起來之后,塊級元素就不固定占用一行了,而是根據(jù)其設(shè)置的寬度顯示。如果一行的寬度能夠容納得下兩個(gè)浮動(dòng)的塊級元素,那么它們就可以同時(shí)顯示在同一個(gè)行內(nèi)。
舉個(gè)簡單地例子,下面的 HTML 片段,設(shè)置了三個(gè) block 元素塊。
<body>
<p class="display">段落1</p>
<p class="display">段落2</p>
<p class="display">段落3</p>
</body>
.display {
display: block;
width: 200px;
height: 100px;
background-color: red;
}
在沒有設(shè)置浮動(dòng)之前,每個(gè)塊級元素都會占用一行,如下圖所示。
-w264
但是如果我們對元素設(shè)置了向左浮動(dòng),那么它們就會往左浮動(dòng),三個(gè)塊級元素都浮動(dòng)到了同一行,如下圖所示。
.display {
display: block;
float: left;
width: 200px;
height: 100px;
background-color: red;
}
-w626
所以,float 元素的出現(xiàn),是用來解決 block 元素塊無法同行顯示,從而無法實(shí)現(xiàn)特定布局場景的問題的。 在 float 出現(xiàn)的很長一段時(shí)間,基本上大家都靠 float 來進(jìn)行頁面布局。
有同學(xué)會問:好像 inline-block 也能實(shí)現(xiàn)這個(gè)效果呀?沒錯(cuò),inline-block 也能實(shí)現(xiàn)這樣的效果。但實(shí)際上,inline-block 是在 float 之后才出現(xiàn)的。 我猜,是 CSS 官方覺得:好像確實(shí)需要有這么一個(gè)屬性值,可以讓多個(gè)元素顯示在同一行,又可以設(shè)置它們的寬高。人民群眾既然需要,那么我們就搞一個(gè) inline-block 給大家用吧!
但從回顧過去,貌似大家用 float 更多一些,用 inline-block 更少一些。為啥呢?或許是 inline-block 出現(xiàn)之前,大家都習(xí)慣用 float 了。而 inline-block 比起 float 貌似沒什么太大的改變,于是就沒動(dòng)力去換了吧。
后來 CSS3 的 flex、grid 出現(xiàn)了,CSS 才真正有了一個(gè)非常好用的布局工具。到了 2023 年的今天,除非是一些需要兼容古老瀏覽器版本的頁面需要用 float 布局,其他大多數(shù)的 Web 頁面布局都使用 flex、grid 進(jìn)行布局了。
看到這里,信息量貌似有點(diǎn)大,怎么去理解 block -> float -> inline-block -> flex/grid 的這種布局變遷呢?知乎某前端大 V 賀師俊的理解,我覺得很好:
言歸正傳,CSS1時(shí)代的網(wǎng)頁還很簡陋,但是隨著萬維網(wǎng)的迅猛發(fā)展,Web界面也迅速進(jìn)化,當(dāng)初簡單的如同書頁般的通欄式網(wǎng)頁迅速絕跡,frameset由于天生存在的一堆問題也很快退出主流,這時(shí)CSS在GUI布局方面就顯出了缺陷,開發(fā)者被迫使用各種trick。比如歷史悠久的table布局。后來table布局被鄙視,開發(fā)者逐漸轉(zhuǎn)向了float布局。
要說float布局之所以流行,IE“功”不可沒。在IE中,has layout的元素是不會環(huán)繞float元素的(因?yàn)閔as layout的元素自己是一個(gè)控件,所以總是保持一個(gè)矩形區(qū)域)。這本來是一個(gè)bug,但是其效果卻正好符合常見的雙欄布局的需要。另外IE下float元素會自動(dòng)撐開其父級container元素(當(dāng)然前提是container元素也是has layout的),這其實(shí)也是bug,但是也恰好符合模塊布局的需求。后來所謂inline-block布局其實(shí)正是這些bug的合理化。
站在今天回望過去十多年的CSS實(shí)踐,我們可以發(fā)現(xiàn),無論float布局還是后來的inline-block布局,其實(shí)都是trick。所謂trick,就是將一些特性挪作他用,以很曲折的方式實(shí)現(xiàn)出想要的效果。CSS作為樣式語言,其可維護(hù)性的最終來源,就是代碼能清晰的表達(dá)出設(shè)計(jì)意圖。而CSS trick當(dāng)然不能很好的滿足這一點(diǎn)。
簡單來說,這樣的布局方式變化,其實(shí)是 CSS 不斷完善進(jìn)化的結(jié)果。一開始的時(shí)候,CSS 的功能比較簡陋,所以需要我們自己用各種 trick 來實(shí)現(xiàn)需要的功能。到了后面,各種應(yīng)用場景日趨完善,CSS 也不斷完善起來,最終我們可以用很簡單的 flex、grid 就實(shí)現(xiàn)之前所需要的效果。
以上關(guān)于 CSS 變遷的理解,來自于賀師俊的知乎回答,感興趣的同學(xué)可以點(diǎn)擊查看原文:在 CSS 中,用 float 和 position 的區(qū)別是什么?- 賀師俊的回答 - 知乎
position
如 position 名字的意思一樣,position 主要是用來調(diào)整元素位置用的。一般情況下,我們用 display 和 float 做好布局之后,可能需要對元素做一些微調(diào),那么這時(shí)候就該 position 登場了。對于 position 來說,其有五個(gè)屬性值,分別是:static、relative、absolute、fixed、sticky。
static
static 關(guān)鍵字指定元素使用正常的布局行為,即元素在文檔常規(guī)流中當(dāng)前的布局位置。
如下圖所示的 HTML 片段,我們不設(shè)置 position 屬性,或者設(shè)置 position 屬性為 static,其展示形式都不發(fā)生變化。
<div class="parent">
<div class="box"></div>
</div>
.parent{
width: 200px;
height: 200px;
border: 1px solid red;
}
.box {
position: static;
width: 50px;
height: 50px;
background-color: black;
}
-w241
relative
relative 表示相對定位,即相對于其父級容器做偏移。偏移位置使用 left/right/top/bottom 屬性來設(shè)置。就如上面的例子中,如果我們使用如下的 CSS 設(shè)置,我們可以看到對應(yīng)的塊元素相對父容器做了偏移,如下圖所示。
.parent{
width: 200px;
height: 200px;
border: 1px solid red;
}
.box {
position: relative;
left: 20px;
top: 20px;
width: 50px;
height: 50px;
background-color: black;
}
-w232
absolute
absolute 表示絕對定位。元素會被移出正常文檔流,并不為元素預(yù)留空間。通過指定元素相對于最近的非 static 定位祖先元素的偏移,來確定元素位置。絕對定位的元素可以設(shè)置外邊距(margins),且不會與其他邊距合并。
如下所示的 HTML 片段,我們使用如下的 CSS 設(shè)置進(jìn)行設(shè)置,那么對應(yīng)元素塊(box類所在元素)的偏移原點(diǎn)就不是其父級元素(son類所在元素),而是最頂層的非 static 定義的祖先元素了(parent類所在元素),如下圖所示。
<body>
<div class="parent">
<div class="son">
<div class="box"></div>
</div>
</div>
</body>
.parent{
position: relative;
top: 50px;
left: 800px;
width: 300px;
height: 200px;
border: 1px solid red;
}
.son {
top: 30px;
left: 30px;
width: 100px;
height: 100px;
border: 1px solid black;
}
.box {
position: absolute;
left: 20px;
top: 20px;
width: 50px;
height: 50px;
background-color: black;
}
-w1245
fixed
fixed 也表示絕對定位。元素會被移出正常文檔流,并不為元素預(yù)留空間,而是通過指定元素相對于屏幕視口(viewport)的位置來指定元素位置。元素的位置在屏幕滾動(dòng)時(shí)不會改變。其與 absolute 的區(qū)別是,fixed 是相對于屏幕 viewport 做偏移的,而 absolute 是相對于最近的一個(gè)非 static 祖先元素做偏移的。
如下所示的 HTML 代碼塊,其與上面 absolute 屬性里的代碼塊完全一致,我們只是將 box 類的 position 屬性值改為了 fixed,如下代碼所示。
<body>
<div class="parent">
<div class="son">
<div class="box"></div>
</div>
</div>
</body>
.parent{
position: relative;
top: 50px;
left: 800px;
width: 300px;
height: 200px;
border: 1px solid red;
}
.son {
top: 30px;
left: 30px;
width: 100px;
height: 100px;
border: 1px solid black;
}
.box {
position: fixed;
left: 20px;
top: 20px;
width: 50px;
height: 50px;
background-color: black;
}
其展示的效果如下圖所示。
-w1184
從這里我們可以較為清晰地看出 absolute 和 fixed 兩個(gè)屬性值的區(qū)別。
sticky
sticky 表示粘性布局,其可以被認(rèn)為是相對定位和固定定位的混合。元素在跨越特定閾值前為相對定位,之后為固定定位。例如:
#one {
position: sticky;
top: 10px;
}
上面的代碼表示:在 viewport 視口滾動(dòng)到元素 top 距離小于 10px 之前,元素為相對定位。等到距離小于 10px 之后,元素將變?yōu)?fixed 定位,元素將固定在與 viewport 頂部距離 10px 的位置。直到元素與 viewport 頂部的距離再次大于 10px,將再次變成相對定位。
一般情況下,這個(gè)用于一些滾動(dòng)查看文本時(shí),需要將某些信息置頂再頂部的情況,如下圖所示。
圖片
在 sticky 屬性之前,我們需要自己做很復(fù)雜的設(shè)置才能實(shí)現(xiàn)這樣的效果。但 sticky 屬性直接幫我們實(shí)現(xiàn)了,非常方便。
CSS 布局解決方案
看到這里,我們基本上把 CSS 布局所需要了解的知識點(diǎn)都介紹了一遍。那我們在實(shí)現(xiàn) Web 頁面的時(shí)候,到底應(yīng)該用哪些 CSS 屬性呢?是 float + block,還是 inlien-blcok,亦或是 flex 呢?
這里我直接給出答案:如果沒有歷史負(fù)擔(dān),不需要去兼容老版本瀏覽器,那么直接上 flex/grid 布局。如果要兼容古老的瀏覽器版本,那么就先用 float,float 解決不了就用 position。
為啥是這樣呢?以為 flex 和 grid 布局是最新的 CSS3 提供的解決方案,是對之前 float + display + position 的總結(jié),是更好的工具。但缺點(diǎn)也明顯,就是一些老版本瀏覽器不兼容,沒法使用。因此要兼容老版本瀏覽器的話,就只能用老古董的 float 這種 tricks 了。
float 布局方式
如果你需要用 float 這種方式去做布局,那可以參考一下這篇文章:【CSS】CSS布局解決方案(終結(jié)版) - 掘金。文章里列舉了不少布局方式,還是比較實(shí)用的,讓你快速掌握常用的布局方式。
我把文章中涉及到的例子都整理到了 CodePen 上,方便大家嘗試,有需要的可以看看:https://codepen.io/Ronald-Chan/pen/wvRdBGL
flex 布局
對于 flex 布局來說,其使用也非常簡單,基本上把對應(yīng)的屬性看一篇就知道怎么玩了。不像 float 布局一樣,需要思來想去的,非常麻煩。
考慮到問文章篇幅和主題問題,關(guān)于如何使用 flex、grid 進(jìn)行排版布局,這里就不延展展開了,后續(xù)有機(jī)會再分享 flex 布局相關(guān)內(nèi)容。
總結(jié)
對于 CSS 布局,之前自己只粗淺地知道 float、display 這些屬性,并沒有深入對比彼此的區(qū)別。當(dāng)然也沒有去了解這些屬性背后的 CSS 發(fā)展歷程,于是很多時(shí)候都會被弄暈。
但這次通過將屬性之間進(jìn)行對比,再深入了解了一下 CSS 的發(fā)展歷程,對 CSS 布局的知識有了整體的了解。知道過去用的是什么方式布局,現(xiàn)在及未來要用什么方式布局,對 CSS 布局就更有底了。
對于 CSS 布局來說,float 方式的布局慢慢會被淘汰,因此不必花大力氣去學(xué)習(xí),只在有需要的時(shí)候?qū)W習(xí)一下就好。我們的學(xué)習(xí)重點(diǎn)應(yīng)該放在 flex、grid 等布局方式的學(xué)習(xí),這也是我后續(xù)的學(xué)習(xí)方向。
關(guān)于 CSS 布局知識的分享就到此為止。希望這篇文章也能給你帶來收獲,讓你更好掌握 CSS 布局技能。如果這篇文章對你有幫助,記得一鍵三連支持我!
參考資料
- CSS 中,position:absolute、float、display:inline-block 都能實(shí)現(xiàn)相同效果,區(qū)別是什么?- 一絲的回答 - 知乎
- CSS3 box-sizing 屬性 | 菜鳥教程
- 官網(wǎng)資料!布局和包含塊 - CSS:層疊樣式表 | MDN
- 介紹 CSS 布局 - 學(xué)習(xí) Web 開發(fā) | MDN
- 【CSS】CSS布局解決方案(終結(jié)版) - 掘金