重學(xué)css(4)深入理解margin

尺寸中padding負(fù)責(zé)內(nèi)邊距,一般情況下(拋開上一章的詭異現(xiàn)象)不會(huì)給使用者帶來太多的麻煩,因此作者稱之為溫和的padding,而margin則有些激進(jìn),雖說負(fù)責(zé)外邊距,但有時(shí)候還能做一些"內(nèi)邊距"的事情(負(fù)邊距),還自帶了些特殊屬性(如疊壓),本文會(huì)通過實(shí)例深入探究margin負(fù)邊距的使用以及疊壓問題的產(chǎn)生和計(jì)算方式

1.margin負(fù)邊距的正確打開方式

說到margin,通常我們會(huì)想到一層透明的外邊距,用于劃分元素與元素之間的界限,然而margin除了可以劃分邊界,還可以改變元素"可視尺寸",注意這里我沒有用內(nèi)部尺寸,因?yàn)閙argin和padding在改變元素可視尺寸方面幾乎是互補(bǔ)的。對于設(shè)定了width或者元素保持"包裹性"的時(shí)候,padding會(huì)改變元素的可視尺寸,而margin正好相反,margin只會(huì)在元素“充分利用空間”狀態(tài)的時(shí)候,才能改變元素的可視尺寸 。當(dāng)然這兩個(gè)也不是完全互補(bǔ)的,這里當(dāng)作一個(gè)思考,請自己體會(huì)。

剛才說到了設(shè)定了寬度的元素和保持“包裹性”的元素不能通過margin影響可視尺寸,設(shè)定width這個(gè)很好理解,那么保持包裹性的元素有哪些呢?

這里來列舉一下常見的有:absolute,fixed,float ,inline-box(inline-block, table-cell, table-caption, flex, inline-flex)。

所以我們在遇到上述元素的時(shí)候,就不需要嘗試用margin去改變他的可視區(qū)了,無效。由于我平時(shí)最愛用的inline-block元素也在其中,所以我很少用margin負(fù)邊距去管理元素可視區(qū)。下面,我們來看一個(gè)最簡單的margin負(fù)邊距影響元素可視區(qū)的演示,代碼如下:

<div class="father">
    <div class="son"></div>
</div>
<style>
.father{
    width: 300px;
    height: 200px;
    background: #F56C6C;
}
.son{
    margin: 0 -20px;
    height: 100px;
    background: #E6A23C;
}
</style>

由于markdown編輯器支持標(biāo)簽語言,因此我們可以直接預(yù)覽最終效果如下(小提示:你可以通過瀏覽器直接檢查下面的元素看到CSS樣式)

這里有兩個(gè)要注意的點(diǎn),首先son是display默認(rèn)為block的元素,符合充分利用水平空間的規(guī)則,其次son自身不帶width申明,所以width在負(fù)邊距的作用下最終width = father.width + 20*2 ,如上圖所示。

負(fù)邊距除了能夠改變"充分可利用空間"的可視區(qū)域之外,還可以利用其可以改變尺寸的特性,實(shí)現(xiàn)一些特殊的布局效果。如作者給出的例子如下:

<div class="box box-right-same">
    <div class="full">
        <p>DOM文檔流中,圖片定寬在右側(cè),視覺呈現(xiàn)也在右側(cè),順便表現(xiàn)此時(shí)一致。</p>
    </div>
    <img src="1.jpg" class="img">
</div>
<style>
/* 右浮動(dòng),圖片DOM在后,和視覺表現(xiàn)一致 */
.box-right-same > .full {
    width: 100%;
    float: left;
}
.box-right-same > .full > p {
    margin-right: 140px;
}
.box-right-same > img {
    float: left;
    margin-left: -128px;
}
</style>

結(jié)果如下圖所示:


結(jié)果如上圖,在本例中,由于full的寬度是100%,且他和img元素均為浮動(dòng)元素,因此img元素在沒有設(shè)置margin之前應(yīng)當(dāng)流到full元素下面,而加了負(fù)邊距之后,img元素的寬度增加了128px,正好等于圖片的寬度,此時(shí)圖片元素全部跑到了增加的負(fù)邊距中去,導(dǎo)致img元素本身變成了"0寬度",于是0寬度元素就浮上來了,因?yàn)樗安恍枰闭紦?jù)寬度,他的寬度由負(fù)邊距提供了。(這一段測試個(gè)人持保留意見,有不同觀點(diǎn)的可在下方留言)

2.深入探究margin合并的三個(gè)條件

塊級(jí)元素的上外邊距(margin-top)和下外邊距(margin-bottom)有時(shí)會(huì)發(fā)生“重疊”,這樣的現(xiàn)象叫做margin合并。從定義上來看,可以確認(rèn)兩個(gè)信息。

(1)塊級(jí)元素

(2)垂直方向。不考慮writing-mode的情況下,文檔流默認(rèn)為水平方向,因此這里的垂直方向是指垂直于文檔流的方向,而不是簡單的上下左右。

margin合并一般有三種場景

(1)相鄰兄弟元素margin合并。

(2)父級(jí)和第一個(gè)/最后一個(gè)子元素。(作者的這個(gè)表達(dá)可能有一些問題,需要配合第三點(diǎn)來看)

(3)空塊級(jí)元素的margin合并。

下面我將列舉一些場景,來探究一下每個(gè)場景的哪些margin發(fā)生了疊壓。

<p>一段話</p>
<p>一段話</p>
<p>一段話</p>
<p>一段話</p>
<style>
p{
    margin: 1em 0;
}
</style>

結(jié)果如下圖所示:

這個(gè)例子中,顯然是相鄰兄弟元素的margin合并,可以看到p標(biāo)簽的上下外邊距是1em,但每兩行之間的的距離并不是1+1=2,而是1和1疊壓之后 = 1。下面來看第二個(gè)場景。

<div class="father">
    <div class="son"></div>
</div>
<style>
body{
    margin: 0;
}
.father{
    background: green;
    height: 400px;
}
.son{
    margin-top: 200px;
    height: 200px;
    background: red;
}
</style>

結(jié)果如下圖所示:

在本例中,父元素高度400,子元素高度200,上外邊距200,想象之中,子元素應(yīng)該"定位"在父容器底部,但由于父級(jí)和第一個(gè)/最后一個(gè)子元素的margin疊壓(這個(gè)理論是否完全正確我們在后面的例子中證明),子元素的margin-top"借"給了父元素,然后自己的margin-top似乎變成了0,在實(shí)際開發(fā)的時(shí)候,父子元素的margin合并也會(huì)給我們帶來許多麻煩,那么,如何解決這個(gè)煩惱呢?作者提供了幾種方案(滿足任何一種即可),這里我會(huì)有一些自己的觀點(diǎn)在里面。

  • (1)父元素設(shè)置為塊狀格式化上下文元素(聽不懂沒關(guān)系,overflow:hidden就可以)

  • (2)父元素設(shè)置border-top/bottom(>0)的值(border-top解決margin-top,border-bottom解決margin-bottom)

  • (3)父元素設(shè)置padding-top/bottom(>0)的值(同border)

  • (4)父元素和第一個(gè)子元素之間添加(非空)內(nèi)聯(lián)元素進(jìn)行分隔(針對margin-top)

  • (5)父元素和最后一個(gè)子元素之間添加(非空)內(nèi)聯(lián)元素進(jìn)行分隔(針對margin-bottom)

  • (6)父元素設(shè)置height,min-height或max-height(注意本條只對margin-bottom有效)

經(jīng)過本人測試,CSS世界似乎對申明這個(gè)玩意不感冒,作者說設(shè)置border/padding的值即可,我設(shè)置0,"竟然"不行,所以補(bǔ)充了>0的限制條件,但由于這條規(guī)則破壞了容器的大小,所以不推薦這兩種解決方案。

在實(shí)際驗(yàn)證的時(shí)候,第四條/第五條在谷歌瀏覽器中也會(huì)由于“0”值不生效,因此我把它劃掉了,因?yàn)檫@個(gè)解決方案實(shí)在是太蠢了,你必須要在內(nèi)聯(lián)元素里面寫點(diǎn)什么才能解決margin疊壓問題,這可比破壞容器大小嚴(yán)重多了,直接就影響文本顯示了。因此最佳的解決方案就是第一條,父元素設(shè)置為塊狀格式化上下文元素,雖然我并不知道這個(gè)是什么意思。

進(jìn)入今天的重頭戲,我覺得作者寫的有問題的一個(gè)點(diǎn),我們先在剛才父子疊壓代碼的基礎(chǔ)上添加一個(gè)空塊級(jí)標(biāo)簽。

<div class="father">
    <!-- 我是一個(gè)空塊級(jí)元素 -->
    <div></div>
    <div class="son"></div>
</div>
<style>
body{
    margin: 0;
}
.father{
    background: green;
    height: 400px;
}
.son{
    margin-top: 200px;
    height: 200px;
    background: red;
}
</style>

此時(shí)你會(huì)發(fā)現(xiàn)頁面無任何變化,其實(shí)這里涉及到兩個(gè)知識(shí)點(diǎn),首先是空塊級(jí)標(biāo)簽的margin疊壓,由于其本身沒有任何寬高,也沒有margin值,因此他只會(huì)和相鄰的son元素進(jìn)行疊壓,空div的margin-bottom:0 和 son元素的margin-top:200合并之后,可以認(rèn)為空div的margin-bottom變成200了,此時(shí),空塊級(jí)元素的margin-bottom:200又和自身的margin-top:0合并,使得自身的margin-top也受到了感染,最后疊壓成垂直margin=200的空塊級(jí)元素,這時(shí)候父元素感應(yīng)到他的第一個(gè)子元素有margin-top,就和他進(jìn)行了一波margin-top疊壓,所以最終的表現(xiàn)和第二個(gè)例子的結(jié)果相同。

測試到這里,我還覺得沒什么問題,然后我又想到剛才內(nèi)聯(lián)空標(biāo)簽對第二個(gè)例子也不會(huì)有任何影響,那么問題來了,父級(jí)和第一個(gè)/最后一個(gè)子元素的疊壓這句話究竟是什么意思?驚覺這句父元素和第一個(gè)子元素之間添加內(nèi)聯(lián)元素進(jìn)行分隔似乎還有什么別的意思,我個(gè)人猜測作者是想表達(dá)內(nèi)聯(lián)元素破壞了發(fā)生疊壓的三個(gè)規(guī)則,因?yàn)閮?nèi)聯(lián)元素不會(huì)發(fā)生margin疊壓,因此可以用這個(gè)進(jìn)行分割(即使該內(nèi)聯(lián)元素為空,當(dāng)然實(shí)際測試中為空是沒有任何效果的)。根據(jù)測試結(jié)果,我提出的一個(gè)大膽的假設(shè):margin疊壓,會(huì)直接忽略掉所有空標(biāo)簽(當(dāng)然空標(biāo)簽不能有什么奇奇怪怪的樣式)。這么一來,內(nèi)聯(lián)空標(biāo)簽的問題就解決了。當(dāng)然這個(gè)假設(shè)還有待驗(yàn)證,去作者提供的論壇碰碰運(yùn)氣。

3.margin合并的計(jì)算規(guī)則

關(guān)于margin合并的計(jì)算規(guī)則,我個(gè)人傾向于完全套用作者的三句精辟總結(jié):
點(diǎn)擊領(lǐng)取免費(fèi)資料及課程

  • “正正取大值”
  • “正負(fù)值相加”
  • “負(fù)負(fù)最負(fù)值”

這里我只說明正負(fù)值相加的情況,雖然這東西其實(shí)并沒有什么軟用,看下面的例子

.a{margin-bottom:50px}
.b{margin-top:-20px}
<div class="a"></div>
<div class="b"></div>
復(fù)制代碼

此時(shí)a和b的間距=-20+50 = 30px

4.深入理解margin:auto

總是喜歡以深入命名,其實(shí)就是一個(gè)??測試,根據(jù)瀏覽器的表現(xiàn)結(jié)果,來猜測原理,在理解margin:auto之前,先來看下面這個(gè)例子。

<div class="father">
    <div class="son"></div>
</div>
<style>
body{
    margin: 0;
}
.father{
    height: 400px;
    background: yellow;
}
.son{
    width: 200px;
    margin-right: 100px;
    margin-left: auto;
    height: 200px;
    background: red;
}
</style>

結(jié)果如下圖所示:

image.png

可以從結(jié)果中得出如下結(jié)論:

(1)margin:auto是有用的,去掉margin-left:auto后,margin-right失效

(2)margin:auto屬性管理的是容器的剩余空間

何為容器的剩余空間?最尋常的情景就是你在body里添加了一個(gè)寬度

image.png

那么問題又出現(xiàn)了,為什么此時(shí)在垂直方向上沒有垂直居中呢?原因在于觸發(fā)margin:auto計(jì)算有一個(gè)前提條件,就是width或height為auto時(shí),元素是具有對應(yīng)方向的自動(dòng)填充屬性的。從本例來看,當(dāng)son的width為auto時(shí),son的寬度為100%,也就是可計(jì)算的剩余空間為100%-width具體值,當(dāng)son的height為auto時(shí),不好意思,son的高度變0了,看都看不見了,你還要居中他干啥。同時(shí)height:auto也不符合自動(dòng)填充特性。

利用margin:auto管理剩余空間的特性,我們除了可以做到元素的水平居中,還可以實(shí)現(xiàn)元素的"右浮動(dòng)"。只需要如下設(shè)置即可.

<div class="father">
    <div class="son"></div>
</div>
<style>
body{
    margin: 0;
}
.father{
    height: 400px;
    background: yellow;
}
.son{
    width: 200px;
    margin-left: auto;
    height: 200px;
    background: red;
}
</style>

這里我們通過margin-left:auto管理剩余空間,元素就自動(dòng)右對齊了。
點(diǎn)擊領(lǐng)取免費(fèi)資料及課程
除了水平居中和右對齊,margin:auto還可以實(shí)現(xiàn)水平垂直居中。剛才也說到了,要實(shí)現(xiàn)垂直居中,只需要讓元素在垂直方向上也就是height:auto具有自動(dòng)填充屬性即可。那么什么情況下height:auto有自動(dòng)填充屬性呢?有一種情況就可以,絕對定位元素設(shè)置了top和bottom屬性之后,元素垂直方向上就會(huì)自動(dòng)填滿父容器。如下所示

<div class="father">
    <div class="son"></div>
</div>
<style>
body{
    margin: 0;
}
.father{
    height: 400px;
    background: yellow;
    position: relative;
}
.son{
    position: absolute;
    width: 200px;
    height: 200px;
    background: red;
    margin: auto;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
}
</style>

由于設(shè)置了right,left,top,bottom值,子元素在水平垂直方向上都有用自動(dòng)填充屬性,通過margin管理剩余空間,就實(shí)現(xiàn)了垂直和水平方向的填充。

margin部分的內(nèi)容就寫到這。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,160評論 1 92
  • 談到margin就不得不提起到css盒模型,盒模型為外邊距+邊框+內(nèi)邊距+內(nèi)容區(qū)域,這里我們不談IE下的怪異模式。...
    Bennt閱讀 1,716評論 2 4
  • 作者:[zhengkonghong](https://coding.net/u/zhengkenghong) 本文...
    CODING_博客閱讀 936評論 1 6
  • 一、CSS入門 1、css選擇器 選擇器的作用是“用于確定(選定)要進(jìn)行樣式設(shè)定的標(biāo)簽(元素)”。 有若干種形式的...
    寵辱不驚丶?xì)q月靜好閱讀 1,729評論 0 6
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,824評論 1 45

友情鏈接更多精彩內(nèi)容