W3C規范在介紹margin時有這樣一句話:
Negative values for margin properties are allowed, but there may be implementation-specific limits.
於是,聰明的開發者們就發現了很多負邊距的巧妙用法。
比如,他可以增加一個不定寬塊框的寬度,他可以讓一個框向上移動去覆蓋另一個框,他可以讓文字移動去覆蓋文字,也可以讓浮動框移動去覆蓋另一個浮動框。
利用這些特點,我們可以實現聖杯布局和雙飛翼布局、等高布局、多列布局等等實用的布局方式。
那么負邊距到底是如何工作的呢?也就是說,這些現象要怎么解釋?
我是這樣理解的:
在可視化格式模型中,一切都是框。所有的框都處於流動狀態。就像是一個個漂浮在水上的小木塊兒,水會將他們往一個地方推。
而邊距,就是用於截流。就像是將一條河截成兩段之后,后一段的水流就無法影響到前一段水流中的小木塊了兒。
普通流(normal flow):
普通流中有塊級格式化上下文和行內級格式化上下文。
在塊級格式化上下文中,塊級框占滿一行,從上到下依次排列。占滿一行意味着,如果他沒有被設置寬度的話,他就會橫向填充滿整個包含框。
所以,塊級格式化上下文中的流應該是這樣的:
所以,給第一個p元素設置margin-bottom:10px;的意思就是在第一個p元素的border-bottom邊線下10px的位置,設置一條攔截線,阻止之后的框被水流沖過這條線。
而如果設置margin-bottom:-10px的話,攔截線就會被設置在第一段文字border-bottom邊線上10px的位置,之后的框會從那里開始流動,也就是會覆蓋住第一段文字10px。按照這個邏輯,在這個例子中,給第一段文字設置margin-bottom:-10px和給的二段文字設置margin-top:-10px的效果是相同的,因為他們都把攔截線設置在了同一個地方。
除了縱向的流外,這里還有兩個橫向的流,一個橫向是塊級框內部的,用於控制他的寬度,另一個是外部的,用於控制他的流向。給一個塊級框設置margin-left: -10px;,那么他的左外邊緣就會被設置在border-left左側10px的位置,他就會去填滿那10px空隙。而如果這時候他剛好沒有被寬度限制的話,他的border-right就不會移動以保證他的寬度。
這也就是為什么給一個不定寬的塊級框設置正邊距會讓他的寬度減小,設置負邊距會讓他的寬度增加。而給一個定寬的塊級框設置左負邊距會讓他左移,設置右負邊距對他沒有影響。
上圖,p1和p2都設置了margin-left: -10px,p2和p3設置了寬度為300px,p3設置了margin-right:-10px;
在行內級格式化上下文中,行級框在水平方向上依次排列,至於是從左到右還是從右到左,由direction屬性決定。如果當前行盒剩余的空間不足以裝下它,他就會折斷,多余的部分換到下一行。縱向的margin值對於行內級框來說無效的,也就是說,行內級框只會受到一個橫向流動的力。
所以,行內級格式化上下文中的流應該是這樣的:
以direction:ltr為例,給第二個行內級框設置margin-left: -20px; margin-right: -20px,結果應該是,他和第三個行內級框向左流動20px后,第三個行內級框又向左移動20px
浮動:
浮動框的上邊緣會去貼當前行盒的上邊緣或是之前浮動框的下邊緣,左浮動框的左邊緣會去貼包含框的左邊緣,或者他之前的左浮動框的右邊緣。如果當前行剩余的空間容不下一個浮動框,他就會換行。(右浮動同理)
一句話描述就是,只要空間夠且無阻礙,浮動框邊緣一定是要挨着包含框content邊緣的。
所以,浮動框的流應該是這樣的:
(三個框都是左浮動,包含框做了清浮動處理,設置了寬度500px。第一個浮動寬為100%,第二個浮動寬為150px,第三個浮動寬為100px.)
浮動流的力量會推它去貼包含框的content邊緣,也就是說,如果一個浮動邊緣已經貼在包含框的content邊緣,且沒有margin的話,在那個方向上,他將不受流動的力量控制。上圖中,第二個浮動的上邊緣被第一個浮動擋住,第三個浮動的左邊緣被第二個浮動擋住,上邊緣被第一個浮動擋住。
如果給第二個浮動設置margin-left:-20px的話,他的左攔截線就會移動到第一個浮動的border-right左側20px的位置:
如果他的margin-left的負值的絕對值大於他自身的寬度,就意味着他的上邊緣不再受第一個浮動的約束,左攔截線也移動到了足以容納他的位置,他就會上移一行,第三個浮動會被一直向左推,直到碰到包含框的左邊緣:
這個時候第二個浮動的負margin絕對值的增大會讓他繼續往左移動,而第三個浮動將不受影響,因為它的左邊緣已經貼在包含框的content左邊緣,已經沒有力量會讓他左移動了,除非,給他設置一個負邊距值,當這個值足夠讓他的上邊界拜托第一個浮動的阻礙時,它也會上移:
絕對定位:
絕對定位的框完全脫離普通流,所以他對其他任何框都不會產生影響,也就意味着,他的margin-left和margin-top會讓他左右和上下移動,而margin-right和margin-bottom則不會產生任何影響。
總結:
邊距用於截流,邊距的正負決定攔截線在對應邊框線的哪一邊(上下左右)。截流之后元素動不動,往哪里動,還是要看它本身處於哪一種流中。