原文: https://www.smashingmagazine....
譯者:前端小智
爲了保證的可讀性,本文采用意譯而非直譯。css
爲了回饋讀者,《大遷世界》不按期舉行(每月一到三次),現金抽獎活動,保底200,外加用戶讚揚,但願你能成爲大遷世界的小錦鯉,快來試試吧
當咱們學習CSS時,咱們大多數人學到的第一件事是CSS中盒子的各個部分的細節,這部分經過叫作 CSS盒、模型。「盒模型」中的元素之一是margin
,即盒子周圍的透明區域,它會將其餘元素從盒子內容中推開。html
CSS1中描述了 margin-top
、margin-right
、margin-bottom
和margin-left
屬性,以及一次設置全部四個屬性的簡寫 margin
。前端
margin
看起來是一個至關簡單的事情,可是,在本文中,我們將看一些在使用margin
一些讓人迷惑有有趣的事情。 特別是,margin
之間如何相互做用,以及 margin
重疊效果。git
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!github
CSS 盒模型指的是一個盒子的各個部分——content
、padding
、border
和margin
,它們各自以前是如何佈局及相互做用的, 以下所示:web
盒子的的四個margin
屬性和maring
縮寫都在CSS1中定義。瀏覽器
CSS2.1規範有一個演示盒模型的插圖,還定義了用來描述各類盒子的術語,其中包括 content box
、填padding box
、border box
和 margin box
。app
如今有一個 Level 3 Box Model specification 的草案。這個規範引用了CSS2做爲盒模型和margin
的定義,所以咱們將在本文的大部份內容中使用CSS2定義。工具
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
。前兩個元素之間的 margin
是50px
,由於較小的頂部 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
可能會相互重疊。在下面的示例中,class
爲empty
的元素的頂部和底部 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 重疊讓人猝不及防,由於它有時候不是很直觀。在下面的示例中,有一個類名爲 wrapper
的div
,給這個div一個紅色的outline
,這樣就能夠看到它在哪裏了。
這個div
裏面的三個子元素的 margin
都是50px
。可是你會發現實際的效果是第一項和最後一項與父元素的的margin
齊平,好像子元素和父元素之間沒有50px
的margin
同樣。
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
。
在CSS2中,只指定垂直方向的 margin
重疊,即元素的頂部和底部 margin。所以,上面的左右邊距不會重疊。
值得注意的,margin 只在塊的方向上重疊,好比段落之間。
若是一個元素是絕對的定位,或者是浮動的,那麼它的margin
永遠不會重疊。然而,假設你遇到了上面示例中的幾種狀況,那麼如何才能阻止 margin 重疊呢?
例如,一個徹底空的盒子,若是它有border
或padding
,它的上下 margin
就不會重疊。在下面的例子中,給這個空盒子添加了1px的padding
。如今這個空盒子的的上方和下方都有一個50px
的 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; padding: 1px; }
運行效果:
這背後是有邏輯,若是盒子是徹底空的,沒有border
或padding
,它基本上是不可見的。 它多是CMS中標記爲空的段落元素。 若是你的CMS添加了多餘的段落元素,你可能不但願它們在其餘段落之間形成較大的空白,這時 margin 重疊就有必定的意義。
對於父元素和第一個或最後一個子元素 margin 重疊,若是咱們向父級添加border
,則子級上的margin
會保留在內部。
... .wrapper { border: 5px dotted black; } ...
一樣,這種行爲也有必定的邏輯。若是出於語義目的而對元素進行包裝,但這些元素不顯示在屏幕上,那麼你可能不但願它們在顯示中引入大的 margin
。當web主要是文本時,這頗有意義。當咱們使用元素來佈局設計時,它的重疊行爲就沒有多大的意義了。
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
容器爲其子元素創建flex
和grid
格式化上下文,所以它們也能阻止 margin
的重疊。
仍是以上面的例子爲例,將 wrapper 改用 flex 佈局:
... .wrapper { outline: 1px solid red; display: flex; flex-direction: column; } ...
因爲margin
會重疊,最好能找到一種一致的方法來處理網站的 margin
。最簡單的方法是隻在元素的頂部或底部定義 margin
。這樣,就不多會遇到 margin 重疊的問題,由於有margin
的邊老是與沒有margin
的邊相鄰。
這個解決方案並不能解決你可能遇到的問題,由於子元素的margin
會與父元素相互重疊。這個特定的問題每每不那麼常見,但知道它爲何會發生能夠幫助你想出一個解決方案。
對此,一個理想的解決方案是給元素設置 display: flow-root
,但有的瀏覽器並不支持,可使用overflow
建立BFC
、或將父元素設置成flex
容器,固然還能夠設置padding
來解決。
當你在CSS中使用百分比的時候,它必須是某個元素的百分比。使用百分比設置的 margin(或 padding)始終是父元素內聯大小(水平寫入模式下的寬度)的百分比。這意味着在使用百分比時,元素周圍的padding
大小都是相同的。
在下面的示例中,有一個200px 寬的 d當,裏面是一個類名爲 box
的div
,它的 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
是如何遵循文本方向的:
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...
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。