前言
致謝
本文總結於 張鑫旭老師的 CSS深入理解之margin課程,感謝張老師的辛苦付出!
難學的 CSS
作為前端狗的我們,每天都要和網頁打交道。當 UI 將設計稿發給你時,CSS 的知識便顯得尤為重要。而 CSS 這一標記性的語言,卻時常讓我很頭疼:毫無邏輯性,並充滿了各種坑爹的潛規則 ,以至於每次做專案時,大部分時間精力都浪費在了調整佈局與樣式上,詳情可點選知乎上的為什麼 CSS 這麼難學?問題,道出了我的心聲 ?
但誰叫我們是吃這碗飯的呢,不管怎樣,有困難必須迎面解決,學好 CSS ,向張老師看齊!
正文
margin 算是性格剛烈的屬性了,下面,我將從各個方面講解 margin 的可怕之處。
元素尺寸的影響
通常一個元素的尺寸可分為:可視尺寸 與 佔據尺寸
- 可視尺寸 – clientWidth (border – padding – size)
- 佔據尺寸 – outerWidth (border – margin)
margin 又是怎樣影響這兩個尺寸的呢?
首先,兩個尺寸都需滿足一定的條件。
可視尺寸的影響條件
- 適用於 沒有設定 width/height 的塊級元素 (寬高設死了,怎麼會影響呢?)
其中不包括 float absolute fixed 元素 ,inline水平 ,table-cell 元素 - 只適用於水平方向尺寸(margin-left/margin-right)
佔據尺寸的影響條件
- 適用於 block/inline-block 水平元素
- 適用於 任何方向
- 與 width/height 值無關
- inline 元素隻影響水平方向 (後面會提到)
影響示例
-
margin 影響元素的可視水平尺寸
See the Pen margin的可視尺寸 by Simon Ma (@Tomotoes) on CodePen.
-
margin 影響佔據尺寸 ,這個可以說是 margin 的本命技能了,就不舉例了。
百分比單位
通常而言,margin 的單位中,百分比單位最容易讓人頭暈。
- 普通元素的百分比 margin 都是相對於 容器的寬度 計算的
<style>
#parent {
margin: 20px 400px;
width: 100px;
height: 200px;
}
#child {
/* 等價於 margin: 5% * 父元素的寬度 10% * 父元素的寬度; */
margin: 5% 10%;
/* 父元素的寬度 * 50% */
width: 50%;
/* 父元素的高度 * 50% */
height: 50%;
}
</style>
<div id="parent">
<div id="child"></div>
</div>
複製程式碼
- 絕對定位的百分比 margin 是相對於 第一個具有定位屬性的祖先元素的寬度 計算的(relative/absolute/fixed)
<style>
#parent {
width: 100px;
}
#child {
/* 注意子元素已增加絕對定位,則百分比按照定位屬性的祖先元素的寬度計算,
本例中是瀏覽器視口 */
position:absolute;
/* 等價於 margin: 5% * 父元素的寬度 10% * 父元素的寬度; */
margin: 5% 10%;
}
</style>
<div id="parent">
<div id="child"></div>
</div>
複製程式碼
重疊詳解
重疊可謂是 margin 中的最重要的潛規則了。
發生情景
- 相鄰的兄弟元素
- 父級和第一個/最後一個子元素
- 空的塊級元素(自己和自己)
重疊條件
- 塊級元素 (不包括 float 和 absolute 元素)
- 不考慮 writing-mode,只發生在垂直方向 (margin-top/margin-bottom)
- 父子 重疊條件
-
margin-top 重疊
- 父元素 非格式化上下文元素 沒有設定 overflow:hidden
- 父元素沒有 border-top 設定
- 父元素沒有 padding-top 設定
- 父元素和第一個子元素之間沒有inline元素分割
-
margin-bottom 重疊
- 父元素 非格式化上下文元素 沒有設定 overflow:hidden
- 父元素沒有 border-bottom 設定
- 父元素沒有 padding-bottom 設定
- 父元素和第一個子元素之間沒有inline元素分割
- 父元素沒有 height ,min-height,max-height 限制
- 空的塊級元素 margin 重疊條件
- 元素沒有 border 設定
- 元素沒有 padding 設定
- 裡面沒有 inline 元素
- 沒有 height,或者 min-height
計算規則
- 正正取大值
<style>
#top{
margin-top:30px;
}
#bottom{
margin-bottom:20px;
}
</style>
<div id="bottom"></div>
<div id="top"></div>
兩個元素垂直距離為 : #top元素的 margin-top值
複製程式碼
- 正負值相加
<style>
#top{
margin-top:-30px;
}
#bottom{
margin-bottom:20px;
}
</style>
<div id="bottom"></div>
<div id="top"></div>
兩個元素垂直距離為: #top元素的margin-top值 加上 #bottom元素的margin-bottom值
複製程式碼
- 負負最負值
<style>
#top{
margin-top:-30px;
}
#bottom{
margin-bottom:-20px;
}
</style>
<div id="bottom"></div>
<div id="top"></div>
兩個元素垂直距離為 : #top元素的 margin-top值
複製程式碼
- 父級和第一個/最後一個子元素 發生重疊
給子元素設定垂直方向的 margin ,等同於 給父元素設定相同的垂直方向的 margin 屬性,
也就是說 父子元素髮生 margin 重疊時, 它們倆共用一個 margin 屬性
重疊意義
- 連續段落或列表之類,如果沒有margin重疊,排版會不自然。
- 頁面中任何地方,巢狀或直接放入任何空的 div,都不會影響原來的佈局。
- 遺落空的任意多個 p 元素,不會影響原來的閱讀排版。
margin auto
當你使用 margin auto
時,就應該聯想到一個詞 :填充
一個沒有設定寬高的塊級元素,會自動填充寬度
如果 一側是定值,一側是 auto,則 auto 為剩餘空間的大小
如果兩側均是 auto,則平分 剩餘空間
示例如下:
<style>
#demo{
width: 500px;
margin-right:100px;
/* margin-left: 100vw - margin-right - width*/
margin-left:auto;
}
</style>
<div id="demo"></div>
複製程式碼
margin:auto 0 !== 垂直居中
以上,我們可得當一個塊級元素設定了 margin: 0 auto
可以實現水平居中,
而為什麼 margin:auto 0 不會垂直居中?
答:一個塊級元素會自動填充可用的水平尺寸,但不會填充垂直尺寸,是因為其根本沒有任何可用的垂直空間。也就是說 margin: 0 auto , 總是有尺寸可以來填充的! 而 margin: auto 0 是沒有任何尺寸的可以來填充的。
失效情況
當子元素的寬度大於父元素的寬度 ,是無法通過 margin: 0 auto 實現居中的
因為,這個時候已經沒有任何空間可以填充了,當寬度超出父元素時,margin 已經為負值了。
垂直居中
- writing-mode 與垂直居中
<style>
.father{
writing-mode: vertical-lr;/* 更改流的方向為 垂直方向 */
}
.son{
margin: auto;
}
</style>
<div class="father">
<div class="son"></div>
</div>
複製程式碼
- 絕對定位元素
<style>
.parent{
position: relative;
}
.child{
position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
margin:auto;
}
</style>
<div class="parent">
<div class="child"></div>
</div>
複製程式碼
失效情景
- inline 水平元素的垂直margin 無效(margin-top/margin-bottom)
- margin 重疊發生
- 絕對定位元素非定位方位的 margin值 “無效”
因為 絕對定位元素 脫離了文件流,與相鄰元素沒有關係,所以它不可能像普通元素一樣,設定margin,推走其他元素 - margin 鞭長莫及
因為 有某些元素破壞了 文件流,設定了 float absolute,造成了假象,margin不會根據 這些破壞元素作為標準 - display:table-cell/display:table-row 等宣告的margin無效!某些替換元素除外,根據各個瀏覽器的實現方式作為區分。比如,給 button 元素宣告 display:table-cell,但在 chrome 中,button 的 display 屬性是 inline-block 。
- 內聯特性導致 margin 失效
margin-top: 負無窮, 但是,小到 1em 便無效了。
因為它是內聯元素,預設是基線對齊,x字母下邊緣對齊,margin 值再大,也不會起作用。
示例如下:See the Pen margin負無窮情景解析 by Simon Ma (@Tomotoes) on CodePen.
其他屬性
- margin-start
- 正常流向,margin-start 等同於 margin-left,兩者重疊不相加
- 如果水平流向是從右向左,margin-start 等同於 margin-right
- 在垂直流下 ( writing-mode:vertical-*; ) margin-start 等同於 margin-top
-
margin-end 與 margin-start 相對
-
margin-before 預設情況等同於 margin-top
-
margin-after 預設情況等同於 margin-bottom
-
margin-collapse
- margin-collapse:collapse;
(預設值) 發生重疊
- margin-collapse:discard;
取消重疊,margin 重疊部分為 0 ,沒有margin
- margin-collapse:separate;
不發生重疊,margin 重疊部分為 margin-top + margin-bottom
結束語
margin 課程就到此結束了,再次感謝張鑫旭老師的辛苦付出!
深入Web全棧各項技術,堅持原創,文章更新雖不定,但只為質量而生,如果您喜歡此篇文章,歡迎支援關注。