盒模型
CSS 框模型 (Box Model) 規(guī)定了元素框處理元素內(nèi)容、內(nèi)邊距、邊框和外邊距的方式。
ps:如果想要深入了解css盒模型,可以去w3cSchool找到關(guān)于盒模型的詳細(xì)概述,這里只會(huì)簡(jiǎn)單的介紹部分盒模型相關(guān)的知識(shí)
什么是CSS盒模型?

這是一個(gè)元素的盒模型展示,幾乎所有元素都是使用這種盒模型構(gòu)成的,盒模型分四個(gè)部分,從里到外分別為element(元素)、padding(內(nèi)邊距)、border(邊框),margin(外邊距)
element
element部分負(fù)責(zé)承載整個(gè)元素的內(nèi)容,如文字、前景圖片等
寫(xiě)在雙閉合標(biāo)簽里面的內(nèi)容通常會(huì)顯示在元素的element部分,也就是內(nèi)容區(qū)。
<div>這里是我的內(nèi)容</div>
頁(yè)面中的顯示效果為:

在上面的中,我在div標(biāo)簽內(nèi)部寫(xiě)了一段文字
這里是我的內(nèi)容,然后這個(gè)div的高度會(huì)被這段文字撐開(kāi),而寬度則是塊級(jí)元素的默認(rèn)寬度100%。
如果我在div內(nèi)部再加一個(gè)圖片,則div的內(nèi)容區(qū)域被繼續(xù)撐開(kāi):
<div>
這里是我的內(nèi)容
<img src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=502636781,1650308494&fm=58">
</div>
呈現(xiàn)效果為:

padding
元素的內(nèi)邊距在邊框和內(nèi)容區(qū)之間。控制該區(qū)域最簡(jiǎn)單的屬性是 padding 屬性。
CSS padding 屬性定義元素邊框與元素內(nèi)容之間的空白區(qū)域。
padding不會(huì)占據(jù)元素的內(nèi)容區(qū)域,但是它會(huì)擴(kuò)展一個(gè)元素的內(nèi)部區(qū)域,可以打一個(gè)比方,我們每個(gè)人本身就好比是一個(gè)元素的element,而你身上穿的衣服就好比是元素的padding部分,你的衣服既是你又不是你本身,別人在找你的時(shí)候如果碰到你的衣服你可以感覺(jué)到是有人觸碰了你,但是你的身體本身并不會(huì)延伸到衣服的內(nèi)部
還是使用上面的那個(gè)div,我們現(xiàn)在給這個(gè)div加上一個(gè)padding,在這之前為了方便觀(guān)察,我們先給這個(gè)div加上一個(gè)背景顏色和寬度,
div {
padding: 10px;
background-color: skyblue;
width:400px;
}
<div style="padding:10px;background-color:skyblue;">
這里是我的內(nèi)容
<img src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=502636781,1650308494&fm=58">
</div>
現(xiàn)在呈現(xiàn)出來(lái)的效果:

我們可以看到,現(xiàn)在文字和圖片還是在這個(gè)元素的底部的,我們現(xiàn)在給他加上一個(gè)50px的padding

我們可以看到,這時(shí)這個(gè)元素本身的大小已經(jīng)擴(kuò)展出來(lái)了,此時(shí)我們可以達(dá)到了瀏覽器的審查元素,觀(guān)察盒模型的變化:

其中藍(lán)色部分是element,也就是元素的內(nèi)容區(qū),400 * 125代表了我們?cè)O(shè)置了400px的寬度,里面的圖片高度是125px,內(nèi)容區(qū)被撐開(kāi),所以此時(shí)元素的內(nèi)容區(qū)是400 * 125像素的大小,然后往外看,padding有4個(gè)50,這是代表了這個(gè)元素在上下左右四個(gè)方向上的padding都是50像素,此時(shí)我們整個(gè)元素的占位寬度就是400+50+50=500px,高度則是125+50+50=225像素,所以但是由于元素內(nèi)容的部分不能延伸到padding區(qū)域,所以上面的文字和圖片還是都在元素本身的內(nèi)容區(qū),不會(huì)隨著元素尺寸被padding撐大而向外擴(kuò)展。
可以被padding擴(kuò)展的樣式
再回到這張圖片

我們可以看到,這個(gè)元素雖然內(nèi)容區(qū)沒(méi)有向padding部分?jǐn)U展,但是背景顏色卻從內(nèi)容區(qū)延伸到了padding的部分,這是因?yàn)樵氐恼w結(jié)構(gòu)以border(邊框)為界,border里面的均為元素的本身部分,而類(lèi)似于
background-color這種樣式會(huì)延展到整個(gè)元素的所有內(nèi)容區(qū)域,和這個(gè)類(lèi)似的效果還有a標(biāo)簽的點(diǎn)擊區(qū)域:
<a href="">這是一個(gè)超級(jí)鏈接</a>

現(xiàn)在我們有一個(gè)a標(biāo)簽構(gòu)成的超級(jí)鏈接,點(diǎn)擊這個(gè)a標(biāo)簽可以跳轉(zhuǎn)到對(duì)應(yīng)的頁(yè)面,但是有的時(shí)候在頁(yè)面中文字可能比較小,如果只有在點(diǎn)擊到文字上時(shí)才能跳轉(zhuǎn)的話(huà)會(huì)影響用戶(hù)體驗(yàn),所以我們要讓a標(biāo)簽的點(diǎn)擊區(qū)域變大,有兩種方式可以解決這個(gè)問(wèn)題:
給a標(biāo)簽寬度和高度
為了方便觀(guān)察,我們同時(shí)給他一個(gè)背景色
a{
width: 300px;
height: 200px;
display: block;
background-color: lightgreen;
}

這時(shí),我們由于擴(kuò)大了a標(biāo)簽的寬度和高度,所以整個(gè)綠色的區(qū)域都是a標(biāo)簽的范圍,自然都可以實(shí)現(xiàn)點(diǎn)擊效果。
給a標(biāo)簽設(shè)置padding
上面那種方式可以實(shí)現(xiàn)大多數(shù)需求,但是現(xiàn)在還有一個(gè)問(wèn)題,就是當(dāng)a標(biāo)簽的可點(diǎn)擊范圍不固定時(shí),或者由于種種問(wèn)題我們不能給a標(biāo)簽轉(zhuǎn)成塊級(jí)元素時(shí),上面那種方法就不生效,比如下面這種場(chǎng)景:

這是一個(gè)通常網(wǎng)頁(yè)中常見(jiàn)的菜單欄,現(xiàn)在我有一個(gè)需求,就是需要給被點(diǎn)擊超級(jí)鏈接加大尺寸方便點(diǎn)擊,同時(shí)加一個(gè)統(tǒng)一的背景顏色,以便于讓用戶(hù)區(qū)分哪些是可以被點(diǎn)擊的區(qū)域。
按照上面的那種方式,我們可以這樣設(shè)置
a{
width: 80px;
height: 30px;
display: block;
background-color: pink;
}
呈現(xiàn)的效果是

這時(shí)如果我們想要給文字居中還需要設(shè)置兩個(gè)樣式:
text-align: center;
line-height: 30px;
然后出來(lái)的效果是這樣的:

這時(shí)我們已經(jīng)達(dá)到了我們所需要的效果,但是還有一種情況,就是當(dāng)列表內(nèi)的文字長(zhǎng)短不一時(shí),這種方式就會(huì)出現(xiàn)問(wèn)題:

如圖所示,當(dāng)我們的列表文字有長(zhǎng)有短時(shí),上面那種方法可能就不太實(shí)用了,因?yàn)檫@時(shí)如果我們?cè)O(shè)置統(tǒng)一的寬度,長(zhǎng)的太長(zhǎng),短的太短,怎么都不好看,處理這樣的情況時(shí),如果不是設(shè)計(jì)稿需要統(tǒng)一長(zhǎng)短,我們一般都會(huì)使用另一種方式排版,即使用統(tǒng)一的padding。
a{
padding: 0 20px;
height: 30px;
display: block;
background-color: pink;
text-align: center;
line-height: 30px;
}

border
元素的邊框 (border) 是圍繞元素內(nèi)容和內(nèi)邊距的一條或多條線(xiàn)。
CSS border 屬性允許你規(guī)定元素邊框的樣式、寬度和顏色。
邊框的使用沒(méi)有什么好說(shuō)的,只有幾個(gè)主要注意的地方:
- 雙線(xiàn)類(lèi)的邊框(如
border-style:double;等),設(shè)置寬度時(shí)最小寬度為3像素,否則不能正常顯示 - border有四個(gè)方向,可以分開(kāi)寫(xiě),如果合寫(xiě)的話(huà)順序同margin和padding的合寫(xiě)順序
- 在使用有邊框的hover效果時(shí),不能直接將邊框設(shè)置為
none,要設(shè)置為border-color:transparent;,hover時(shí)再將顏色設(shè)置回需要的顏色,否則會(huì)出現(xiàn)高度顯示異常的問(wèn)題。
其中1、2比較容易理解,下面解釋一下第3點(diǎn)。
我們?cè)谧鲰?yè)面的時(shí)候,有的時(shí)候會(huì)使用這樣的特效:

和這樣的特效:

為了讓效果看起來(lái)更明顯,我延長(zhǎng)了動(dòng)畫(huà)執(zhí)行時(shí)間并且降低了幀數(shù)
下面是兩個(gè)效果的代碼:
border.gif
a{
padding: 0 20px;
height: 30px;
display: block;
text-align: center;
line-height: 30px;
}
a:hover{
border-bottom: 4px solid red;
}
border-transition.gif
a{
padding: 0 20px;
height: 30px;
display: block;
text-align: center;
line-height: 30px;
border-bottom: 4px solid transparent;
transition: all 1s;
}
a:hover{
border-bottom: 4px solid red;
}
這兩種效果最大的區(qū)別在于2比1多了一個(gè)過(guò)渡的效果。
按照沒(méi)有過(guò)渡效果的border(以下簡(jiǎn)稱(chēng)效果1)的思路,轉(zhuǎn)變成有過(guò)渡效果的border(簡(jiǎn)稱(chēng)效果2)應(yīng)該只需要加一個(gè)transition作過(guò)渡動(dòng)畫(huà)就可以了,但實(shí)際上如果我們只是在效果1的基礎(chǔ)上加了一個(gè)transition的話(huà)則會(huì)出現(xiàn)這樣的效果:

這是由于HTML在繪制元素生成時(shí)會(huì)從上至下繪制,而不是所有像素同時(shí)繪制,最開(kāi)始時(shí)a標(biāo)簽內(nèi)沒(méi)有邊框,hover時(shí)出現(xiàn)邊框,HTML就會(huì)從沒(méi)有邊框開(kāi)始一行行繪制,所以就會(huì)出現(xiàn)這樣的效果,如果這個(gè)菜單是放在頁(yè)面中可能會(huì)出現(xiàn)邊框?qū)⑸厦娴奈淖猪斏先サ男Ч?br> 因此我們這里需要先讓a標(biāo)簽有一個(gè)透明的邊框,鼠標(biāo)放上去時(shí)只是讓邊框變顏色,才會(huì)出現(xiàn)我們想要的效果。
margin
圍繞在元素邊框的空白區(qū)域是外邊距。設(shè)置外邊距會(huì)在元素外創(chuàng)建額外的“空白”。
設(shè)置外邊距的最簡(jiǎn)單的方法就是使用 margin 屬性,這個(gè)屬性接受任何長(zhǎng)度單位、百分?jǐn)?shù)值甚至負(fù)值。
在初學(xué)css時(shí),margin和padding最容易混淆,實(shí)際上我們只需要注意兩者最大的區(qū)別就可以,那就是padding可以延伸background的屬性,主要是background-color和backgound-image,而margin不會(huì)延伸這些屬性。
<style>
div{
width: 200px;
height: 200px;
}
.div1{
background-color: pink;
}
.div2{
background-color: green;
}
</style>
</head>
<body>
<div class="div1">這是div1的內(nèi)容</div>
<div class="div2"></div>
</body>
我在這里寫(xiě)了兩個(gè)div,給他們加了同樣的寬度并分別加了背景顏色,同時(shí)給div1加了幾個(gè)文字內(nèi)容,由于塊級(jí)元素的特性,他們分別處于兩排。

現(xiàn)在我給div1設(shè)置50px的padding
.div1{
background-color: pink;
padding: 50px;
}

可以看到,現(xiàn)在div1的元素本身被撐大了,現(xiàn)在div1的高應(yīng)該是50 + 200 + 50 = 300px

同樣,由于上面提到的padding的特性,所以文字依然是在內(nèi)容區(qū),沒(méi)有進(jìn)入padding的部分。
此時(shí)我們可以看到,div1的整體尺寸被放大了,同時(shí)背景顏色延伸到padding的范圍。
現(xiàn)在我再給div1設(shè)置5px的border
.div1{
background-color: pink;
padding: 50px;
border: 5px solid red;
}
這時(shí)div1的整體高度應(yīng)該是5 + 50 + 200 + 50 + 5 = 310px

然后再設(shè)置20px的margin:
.div1{
background-color: pink;
padding: 50px;
border: 5px solid red;
margin: 20px;
}

設(shè)置的樣式是margin:20px;由于截圖問(wèn)題,可能顯示的有問(wèn)題
我們先不用管其他方向,先看下面,也就是div1和div2交接的地方。
在這里我們可以看到div1和div2之間有20px的間距,這一部分就是div1的margin,而且和padding最大的區(qū)別是這一部分沒(méi)有延伸div1的背景色和內(nèi)容區(qū)域,同時(shí)也沒(méi)有讓div的元素尺寸發(fā)生改變

因此我們可以這樣理解
- element是你的身體,你的身體越胖element越大,而你體內(nèi)的元素(如血液、氧氣)可以在你體內(nèi)自由流動(dòng)
- padding是你身上衣服的薄厚,你的身體占位(尺寸)和padding正相關(guān),但是你體內(nèi)的元素不能接觸到padding
- border是你衣服最外層的皮革,皮革同樣會(huì)延展你的身體占位
- margin是你的氣場(chǎng),雖然沒(méi)有元素阻隔,但是如果你的氣場(chǎng)夠強(qiáng)大,其他人也不能靠近你
這里看完了,我們現(xiàn)在再回頭看margin右側(cè)的問(wèn)題

我們可以發(fā)現(xiàn),Chrome在審核元素時(shí)會(huì)自動(dòng)將對(duì)應(yīng)部位改變顏色,在右側(cè)鼠標(biāo)放在對(duì)應(yīng)的位置時(shí),左側(cè)的元素也會(huì)實(shí)時(shí)響應(yīng)出對(duì)應(yīng)位置,如圖所示,在element、padding、border時(shí)顯示均正常,margin時(shí)上、左、下三個(gè)方向也沒(méi)有問(wèn)題,唯獨(dú)右側(cè)會(huì)比我設(shè)置的margin要大得多(margin:20px),這是因?yàn)閴K級(jí)元素獨(dú)占一行的特性,讓他在自己元素本身同行的位置會(huì)有默認(rèn)的margin:auto;,即同行下所有元素沒(méi)有占的位置均為這個(gè)元素的margin,這也是塊級(jí)元素不能和其他元素同行的原因。

應(yīng)用技巧
元素的盒模型會(huì)有各種各樣特殊的問(wèn)題,下面舉幾個(gè)常見(jiàn)的例子以及經(jīng)常出現(xiàn)的問(wèn)題和解決方式:
元素高度問(wèn)題
我們?cè)诓季謺r(shí),由于元素的高度通常為后臺(tái)提供,所以前端頁(yè)面的部分通常不會(huì)給固定的高度以免結(jié)構(gòu)混亂,所以我們?cè)诓季謺r(shí)需要靈活運(yùn)用padding和清浮動(dòng)。

上面一個(gè)div內(nèi)部有一個(gè)ul無(wú)序列表,div上下均距離ul有一定的距離。
在我們寫(xiě)靜態(tài)頁(yè)面時(shí)無(wú)序列表的數(shù)量可能是固定的(4個(gè)),但是js加載時(shí)通常數(shù)量不固定,可能少于4個(gè)也有可能更多,這時(shí)如果我們給一個(gè)固定的高度則會(huì)出現(xiàn)內(nèi)容溢出的問(wèn)題

所以這里我們需要給div設(shè)置上下相等的padding,而不是固定高度。

在使用
padding進(jìn)行內(nèi)容填充時(shí)需要注意padding會(huì)延展這個(gè)元素本身的尺寸,所以如果同時(shí)設(shè)置了元素的height和padding時(shí),要將元素的盒模型改成border-box或在height里面減去padding所占的像素;如元素本身的高度是100px,如果你又設(shè)置了padding:10px 0;,那么你需要將高度減去20px,即改為80px。
margin-top的bug
在HTML中,一個(gè)元素內(nèi)部的第一個(gè)子元素如果有margin-top的話(huà)即會(huì)將子元素的margin-top賦給父元素:
<style>
body{
background-color: lightblue;
}
div {
background-color: #eee;
height: 300px;
}
h1 {
margin-top: 50px;
}
</head>
<body>
<div>
<h1>標(biāo)題部分</h1>
</div>
</body>

如圖所示,我在元素中給h1設(shè)置了margin-top,但是h1的margin-top并沒(méi)有生效,而是傳遞給了它的父元素div,導(dǎo)致div整個(gè)被拉了下來(lái),布局錯(cuò)亂。
觸發(fā)原因
一個(gè)盒子如果沒(méi)有上補(bǔ)白(padding-top)和上邊框(border-top),那么這個(gè)盒子的上邊距會(huì)和其內(nèi)部文檔流中的第一個(gè)子元素的上邊距重疊。
解決方法:
- 給父元素設(shè)置
border-top:1px; - 將子元素的margin-top改成同等數(shù)量的padding-top,并賦給父元素
兩種解決方法中,方法2最常用