CSS進階(5)—— 深刻理解margin

盒尺寸中padding負責內邊距,通常狀況下(拋開上一章的詭異現象)不會給使用者帶來太多的麻煩,所以做者稱之爲溫和的padding,而margin則有些激進,雖然說負責外邊距,但有時候還能作一些"內邊距"的事情(負邊距),還自帶了些特殊屬性(如疊壓),本文會經過實例深刻探究margin負邊距的使用以及疊壓問題的產生和計算方式css

1.margin負邊距的正確打開方式

說到margin,一般咱們會想到一層透明的外邊距,用於劃分元素與元素之間的界限,然而margin除了能夠劃分邊界,還能夠改變元素"可視尺寸",注意這裏我沒有用內部尺寸,由於margin和padding在改變元素可視尺寸方面幾乎是互補的。對於設定了width或者元素保持"包裹性"的時候,padding會改變元素的可視尺寸,而margin正好相反,margin只會在元素「充分利用空間」狀態的時候,才能改變元素的可視尺寸 。固然這兩個也不是徹底互補的,這裏看成一個思考,請本身體會。 html

剛纔說到了設定了寬度的元素和保持「包裹性」的元素不能經過margin影響可視尺寸,設定width這個很好理解,那麼保持包裹性的元素有哪些呢? 瀏覽器

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

因此咱們在遇到上述元素的時候,就不須要嘗試用margin去改變他的可視區了,無效。因爲我平時最愛用的inline-block元素也在其中,因此我不多用margin負邊距去管理元素可視區。下面,咱們來看一個最簡單的margin負邊距影響元素可視區的演示,代碼以下: 編輯器

<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編輯器支持標籤語言,所以咱們能夠直接預覽最終效果以下(小提示:你能夠經過瀏覽器直接檢查下面的元素看到CSS樣式) 佈局

這裏有兩個要注意的點,首先son是display默認爲block的元素,符合充分利用水平空間的規則,其次son自身不帶width申明,因此width在負邊距的做用下最終width = father.width + 20*2 ,如上圖所示。 測試

負邊距除了可以改變"充分可利用空間"的可視區域以外,還能夠利用其能夠改變尺寸的特性,實現一些特殊的佈局效果。如做者給出的例子以下: flex

<div class="box box-right-same">
    <div class="full">
        <p>DOM文檔流中,圖片定寬在右側,視覺呈現也在右側,順便表現此時一致。</p>
    </div>
    <img src="1.jpg" class="img">
</div>
<style> /* 右浮動,圖片DOM在後,和視覺表現一致 */ .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>
複製代碼

結果以下圖所示: spa

結果如上圖,在本例中,因爲full的寬度是100%,且他和img元素均爲浮動元素,所以img元素在沒有設置margin以前應當流到full元素下面,而加了負邊距以後,img元素的寬度增長了128px,正好等於圖片的寬度,此時圖片元素所有跑到了增長的負邊距中去,致使img元素自己變成了"0寬度",因而0寬度元素就浮上來了,由於他「不須要」佔據寬度,他的寬度由負邊距提供了。(這一段測試我的持保留意見,有不一樣觀點的可在下方留言) 3d

2.深刻探究margin合併的三個條件

塊級元素的上外邊距(margin-top)和下外邊距(margin-bottom)有時會發生「重疊」,這樣的現象叫作margin合併。從定義上來看,能夠確認兩個信息。

(1)塊級元素

(2)垂直方向。不考慮writing-mode的狀況下,文檔流默認爲水平方向,所以這裏的垂直方向是指垂直於文檔流的方向,而不是簡單的上下左右。

margin合併通常有三種場景

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

(2)父級和第一個/最後一個子元素。(做者的這個表達可能有一些問題,須要配合第三點來看)

(3)空塊級元素的margin合併。

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

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

結果以下圖所示:

這個例子中,顯然是相鄰兄弟元素的margin合併,能夠看到p標籤的上下外邊距是1em,但每兩行之間的的距離並非1+1=2,而是1和1疊壓以後 = 1。下面來看第二個場景。

<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>
複製代碼

結果以下圖所示:

在本例中,父元素高度400,子元素高度200,上外邊距200,想象之中,子元素應該"定位"在父容器底部,但因爲父級和第一個/最後一個子元素的margin疊壓(這個理論是否徹底正確咱們在後面的例子中證實),子元素的margin-top"借"給了父元素,而後本身的margin-top彷佛變成了0,在實際開發的時候,父子元素的margin合併也會給咱們帶來許多麻煩,那麼,如何解決這個煩惱呢?做者提供了幾種方案(知足任何一種便可),這裏我會有一些本身的觀點在裏面。

  • (1)父元素設置爲塊狀格式化上下文元素(聽不懂不要緊,overflow:hidden就能夠)

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

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

  • (4)父元素和第一個子元素之間添加(非空)內聯元素進行分隔(針對margin-top)

  • (5)父元素和最後一個子元素之間添加(非空)內聯元素進行分隔(針對margin-bottom)

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

通過本人測試,CSS世界彷佛對申明這個玩意不感冒,做者說設置border/padding的值便可,我設置0,"居然"不行,因此補充了>0的限制條件,但因爲這條規則破壞了容器的大小,因此不推薦這兩種解決方案。

在實際驗證的時候,第四條/第五條在谷歌瀏覽器中也會因爲「0」值不生效,所以我把它劃掉了,由於這個解決方案實在是太蠢了,你必需要在內聯元素裏面寫點什麼才能解決margin疊壓問題,這可比破壞容器大小嚴重多了,直接就影響文本顯示了。所以最佳的解決方案就是第一條,父元素設置爲塊狀格式化上下文元素,雖然我並不知道這個是什麼意思。

進入今天的重頭戲,我以爲做者寫的有問題的一個點,咱們先在剛纔父子疊壓代碼的基礎上添加一個空塊級標籤。

<div class="father">
    <!-- 我是一個空塊級元素 -->
    <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>
複製代碼

此時你會發現頁面無任何變化,其實這裏涉及到兩個知識點,首先是空塊級標籤的margin疊壓,因爲其自己沒有任何寬高,也沒有margin值,所以他只會和相鄰的son元素進行疊壓,空div的margin-bottom:0 和 son元素的margin-top:200合併以後,能夠認爲空div的margin-bottom變成200了,此時,空塊級元素的margin-bottom:200又和自身的margin-top:0合併,使得自身的margin-top也受到了感染,最後疊壓成垂直margin=200的空塊級元素,這時候父元素感應到他的第一個子元素有margin-top,就和他進行了一波margin-top疊壓,因此最終的表現和第二個例子的結果相同。

測試到這裏,我還以爲沒什麼問題,而後我又想到剛纔內聯空標籤對第二個例子也不會有任何影響,那麼問題來了,父級和第一個/最後一個子元素的疊壓這句話到底是什麼意思?驚覺這句父元素和第一個子元素之間添加內聯元素進行分隔彷佛還有什麼別的意思,我我的猜想做者是想表達內聯元素破壞了發生疊壓的三個規則,由於內聯元素不會發生margin疊壓,所以能夠用這個進行分割(即便該內聯元素爲空,固然實際測試中爲空是沒有任何效果的)。根據測試結果,我提出的一個大膽的假設:margin疊壓,會直接忽略掉全部空標籤(固然空標籤不能有什麼奇奇怪怪的樣式)。這麼一來,內聯空標籤的問題就解決了。固然這個假設還有待驗證,去做者提供的論壇碰碰運氣。

3.margin合併的計算規則

關於margin合併的計算規則,我我的傾向於徹底套用做者的三句精闢總結:

  • 「正正取大值」
  • 「正負值相加」
  • 「負負最負值」

這裏我只說明正負值相加的狀況,雖然這東西其實並無什麼軟用,看下面的例子

.a{margin-bottom:50px}
.b{margin-top:-20px}
<div class="a"></div>
<div class="b"></div>
複製代碼

此時a和b的間距=-20+50 = 30px

4.深刻理解margin:auto

老是喜歡以深刻命名,其實就是一個🐶測試,根據瀏覽器的表現結果,來猜想原理,在理解margin:auto以前,先來看下面這個例子。

<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>
複製代碼

結果以下圖所示:

能夠從結果中得出以下結論:

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

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

何爲容器的剩餘空間?最尋常的情景就是你在body裏添加了一個寬度

那麼問題又出現了,爲何此時在垂直方向上沒有垂直居中呢?緣由在於觸發margin:auto計算有一個前提條件,就是width或height爲auto時,元素是具備對應方向的自動填充屬性的。從本例來看,當son的width爲auto時,son的寬度爲100%,也就是可計算的剩餘空間爲100%-width具體值,當son的height爲auto時,很差意思,son的高度變0了,看都看不見了,你還要居中他幹啥。同時height:auto也不符合自動填充特性。

利用margin:auto管理剩餘空間的特性,咱們除了能夠作到元素的水平居中,還能夠實現元素的"右浮動"。只須要以下設置便可.

<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管理剩餘空間,元素就自動右對齊了。

除了水平居中和右對齊,margin:auto還能夠實現水平垂直居中。剛纔也說到了,要實現垂直居中,只須要讓元素在垂直方向上也就是height:auto具備自動填充屬性便可。那麼什麼狀況下height:auto有自動填充屬性呢?有一種狀況就能夠,絕對定位元素設置了top和bottom屬性以後,元素垂直方向上就會自動填滿父容器。以下所示

<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>
複製代碼

因爲設置了right,left,top,bottom值,子元素在水平垂直方向上都有用自動填充屬性,經過margin管理剩餘空間,就實現了垂直和水平方向的填充。

margin部分的內容就寫到這。

不忘初心,方得始終

喜歡博主的童鞋能夠掃描二維碼加博主好友~ 也能夠掃中間二維碼入駐博主的粉絲羣(708637831)~固然你也能夠掃描二維碼打賞並直接包養帥氣的博主一枚。

相關文章
相關標籤/搜索