關於 CSS margin,一些讓你模糊的點

原文: https://www.smashingmagazine....
譯者:前端小智

爲了保證的可讀性,本文采用意譯而非直譯。css

爲了回饋讀者,《大遷世界》不按期舉行(每月一到三次),現金抽獎活動,保底200,外加用戶讚揚,但願你能成爲大遷世界的小錦鯉,快來試試吧

當咱們學習CSS時,咱們大多數人學到的第一件事是CSS中盒子的各個部分的細節,這部分經過叫作 CSS盒、模型。「盒模型」中的元素之一是margin,即盒子周圍的透明區域,它會將其餘元素從盒子內容中推開。html

CSS1中描述了 margin-topmargin-rightmargin-bottommargin-left屬性,以及一次設置全部四個屬性的簡寫 margin前端

margin看起來是一個至關簡單的事情,可是,在本文中,我們將看一些在使用margin一些讓人迷惑有有趣的事情。 特別是,margin之間如何相互做用,以及 margin 重疊效果。git

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!github

CSS 盒模型

CSS 盒模型指的是一個盒子的各個部分——contentpaddingbordermargin,它們各自以前是如何佈局及相互做用的, 以下所示:web

盒子的的四個margin屬性和maring縮寫都在CSS1中定義。瀏覽器

CSS2.1規範有一個演示盒模型的插圖,還定義了用來描述各類盒子的術語,其中包括 content box、填padding boxborder boxmargin boxapp

如今有一個 Level 3 Box Model specification 的草案。這個規範引用了CSS2做爲盒模型和margin的定義,所以咱們將在本文的大部份內容中使用CSS2定義。工具

margin 重疊

CSS1 規範定義了margin,也定義了垂直 margin 重疊。若是考慮到在早期,CSS被用做文檔格式語言,那麼 margin 重疊是有意義的。 margin 重疊意味着,當一個有底部margin的標題後面跟着一個有頂部 margin 的段落時,它們之間就不會出現較大的空白。佈局

當兩個 margin 發生重疊時,它們將組合在一塊兒,兩個元素之間的空間取較大的一個。 較小的 margin 在較大的裏面。

在如下狀況下,margin 會重疊:

  • 相鄰的兄弟姐妹
  • 徹底空盒子
  • 父元素和第一個或最後一個子元素

依次來看看這些場景。

相鄰的兄弟姐妹

margin 重疊的最初描述是演示相鄰兄弟姐妹之間的 margin 是如何重疊的。除了下面提到的狀況以外,若是有兩個元素在正常流中依次顯示,那麼第一個元素的底部 margin 將與下面元素的頂部 margin 一塊兒重疊。

在下面示例中,有三個div元素。第一個 div 的頂部和底部的margin都是50px。第二個 div 的頂部和底部 margin 都是20px。第三個 div 的頂部和底部 margin 都是3em。前兩個元素之間的 margin50px,由於較小的頂部 margin 與較大的底部 margin 相結合。第二個元素與第三個元素之間的 margin 是 3em,由於3em大於第二個元素底部margin 20px。

html

<div class="wrapper">

<div class="box example1">
  margin-top: 50px; margin-bottom: 50px;
</div>

<div class="box example2">
  margin-top: 20px; margin-bottom: 20px;
</div>

<div class="box example3">
  margin-top: 3em; margin-bottom: 3em;
</div>
  
</div>

css

.wrapper {
  border: 5px dotted black;
}

.example1 {
  margin: 50px 0 50px 0;
}

.example2 {
  margin: 20px 0 20px 0;
}

.example3 {
  margin: 3em 0 3em 0;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  padding: 20px;
  border-radius: .5em;
}

運行效果:

徹底空盒子

若是一個盒子是空的,那麼它的頂部和底部 margin 可能會相互重疊。在下面的示例中,classempty的元素的頂部和底部 margin 各爲50px,可是,第一項和第三項之間的 margin不是100px,而是50px。這是因爲兩個 margin 重疊形成的。若是向空盒子中放入內容就會阻止 margin 合併。

html

div class="wrapper">

<div class="box">
  A box
</div>

<div class="box empty"></div>

<div class="box">
  Another box
</div>
  
</div>

css

.wrapper {
  border: 5px dotted black;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  border-radius: .5em;
}

.empty {
  margin: 50px 0 50px 0;
}

運行效果:

父元素和第一個或最後一個子元素

margin 重疊讓人猝不及防,由於它有時候不是很直觀。在下面的示例中,有一個類名爲 wrapperdiv,給這個div一個紅色的outline,這樣就能夠看到它在哪裏了。

這個div裏面的三個子元素的 margin 都是50px。可是你會發現實際的效果是第一項和最後一項與父元素的的margin齊平,好像子元素和父元素之間沒有50pxmargin同樣。

html

<div class="wrapper">

<div class="box">
  Item 1
</div>

<div class="box">
  Item 2
</div>

<div class="box">
  Item 3
</div>
  
</div>

css

.wrapper {
  outline: 1px solid red;
}

.box {
  margin: 50px;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  padding: 20px;
  border-radius: .5em;
}

運行效果:

這是由於子節點上的margin會隨着父節點上的任何一邊的margin相互重疊,從而最終位於父節點的外部。若是使用DevTools檢查第一個子元素,就能夠看到這一點,顯示的黃色區域就是是 margin

僅塊元素 margin 重疊

在CSS2中,只指定垂直方向的 margin 重疊,即元素的頂部和底部 margin。所以,上面的左右邊距不會重疊。

值得注意的,margin 只在塊的方向上重疊,好比段落之間。

阻止 margin 重疊

若是一個元素是絕對的定位,或者是浮動的,那麼它的margin永遠不會重疊。然而,假設你遇到了上面示例中的幾種狀況,那麼如何才能阻止 margin 重疊呢?

例如,一個徹底空的盒子,若是它有borderpadding,它的上下 margin就不會重疊。在下面的例子中,給這個空盒子添加了1px的padding。如今這個空盒子的的上方和下方都有一個50pxmargin

html

<div class="wrapper">

<div class="box">
  A box
</div>

<div class="box empty"></div>

<div class="box">
  Another box
</div>
  
</div>

css

.wrapper {
  border: 5px dotted black;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  border-radius: .5em;
}

.empty {
  margin: 50px 0 50px 0;
  padding: 1px;
}

運行效果:

這背後是有邏輯,若是盒子是徹底空的,沒有borderpadding,它基本上是不可見的。 它多是CMS中標記爲空的段落元素。 若是你的CMS添加了多餘的段落元素,你可能不但願它們在其餘段落之間形成較大的空白,這時 margin 重疊就有必定的意義。

對於父元素和第一個或最後一個子元素 margin 重疊,若是咱們向父級添加border,則子級上的margin會保留在內部。

...
.wrapper {
  border: 5px dotted black;
}
...

一樣,這種行爲也有必定的邏輯。若是出於語義目的而對元素進行包裝,但這些元素不顯示在屏幕上,那麼你可能不但願它們在顯示中引入大的 margin。當web主要是文本時,這頗有意義。當咱們使用元素來佈局設計時,它的重疊行爲就沒有多大的意義了。

建立格式化上下文(BFC)

BFC(Block Formatting Context)格式化上下文,是Web頁面中盒模型佈局的CSS渲染模式,指一個獨立的渲染區域或者說是一個隔離的獨立容器。

BFC 能夠阻止邊距的重疊。 若是咱們再看父元素和第一個或最後一個子元素的示例,能夠在 wrapper 元素加上 display: flow-root就會建立一個新的BFC,從而阻止 margin 合併

...
.wrapper {
  outline: 1px solid red;
  display: flow-root;
}
...

display: flow-root 是CSS3新出來的一個屬性,用來建立一個無反作用的 BFC。將overflow屬性的值設爲auto也會產生一樣的效果,由於這也建立了一個新的BFC,儘管它也可能建立一些在某些場景中不須要的滾動條。

flex 和 grid 容器

flexgrid 容器爲其子元素創建flexgrid格式化上下文,所以它們也能阻止 margin 的重疊。

仍是以上面的例子爲例,將 wrapper 改用 flex 佈局:

...
.wrapper {
  outline: 1px solid red;
  display: flex;
  flex-direction: column;
}
...

網站 margin 策略

因爲margin 會重疊,最好能找到一種一致的方法來處理網站的 margin。最簡單的方法是隻在元素的頂部或底部定義 margin。這樣,就不多會遇到 margin 重疊的問題,由於有margin的邊老是與沒有margin的邊相鄰。

這個解決方案並不能解決你可能遇到的問題,由於子元素的margin會與父元素相互重疊。這個特定的問題每每不那麼常見,但知道它爲何會發生能夠幫助你想出一個解決方案。

對此,一個理想的解決方案是給元素設置 display: flow-root,但有的瀏覽器並不支持,可使用overflow建立BFC、或將父元素設置成flex容器,固然還能夠設置padding來解決。

百分比 margin

當你在CSS中使用百分比的時候,它必須是某個元素的百分比。使用百分比設置的 margin(或 padding)始終是父元素內聯大小(水平寫入模式下的寬度)的百分比。這意味着在使用百分比時,元素周圍的padding大小都是相同的。

在下面的示例中,有一個200px 寬的 d當,裏面是一個類名爲 boxdiv,它的 margin值爲10%,也就是 20px (200*10%)。

html

<div class="wrapper">
  <div class="box">
    I have a margin of 10%.
  </div>
</div>

css

* {
  box-sizing: border-box;
}

.wrapper {
  border: 5px dotted black;
  width: 200px;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  padding: 20px;
  border-radius: .5em;
  margin: 10%;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

咱們在本文中一直在討論垂直 margin ,然而,現代CSS傾向於以相對於流的方式而不是物理方式來考慮事情。所以,當咱們討論垂直邊距時,咱們其實是在討論塊維度的邊距。若是咱們在水平寫做模式下,這些 margin 將是頂部和底部,但在垂直寫做模式下,這些 margin 將是右側和左側。

一旦使用邏輯的、流相關的方向,就更容易討論塊的開始和結束,而不是塊的頂部和底部。爲了簡化這一過程,CSS引入了邏輯屬性和值規範。這將流的相關屬性映射到物理屬性上。

  • margin-top = margin-block-start
  • margin-right = margin-inline-end
  • margin-bottom = margin-block-end
  • margin-left = margin-inline-start

還有兩個新的快捷鍵,能夠同時設置兩個塊或者兩個內嵌塊。

  • margin-block
  • margin-inline

在下面示例中,使用了這些流相關關鍵字,而後更改了盒子的編寫模式,你能夠看到 margin 是如何遵循文本方向的:

html

<div class="wrapper horizontal-tb">
  <div class="box">
    A box with a horizontal-tb writing mode.
  </div>
</div>

<div class="wrapper vertical-rl">
  <div class="box">
    A box with a vertical-rl writing mode.
  </div>
</div>

css

* {
  box-sizing: border-box;
}

.wrapper {
  border: 5px dotted black;
  inline-size: 200px;
}

.horizontal-tb {
  writing-mode: horizontal-tb;
  margin-bottom: 1em;
}

.vertical-rl {
  writing-mode: vertical-rl;
}

.box {
  background-color: rgb(55,55,110);
  color: white;
  padding: 20px;
  border-radius: .5em;
  margin-block-start: 30px;
  margin-block-end: 10px;
  margin-inline-start: 2em;
  margin-inline-end: 5%;
}

body {
  font: 1.4em/1.3 "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
  margin: 2em 3em;
}

須要瞭解更多,能夠閱讀有關MDN上的邏輯屬性和值的更多信息。

代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

交流

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

https://github.com/qq44924588...

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

相關文章
相關標籤/搜索