深入理解css中的margin屬性(最新瀏覽器支持)

本文啓發於博客園一篇2016年的“深入理解css中的margin屬性”文章,根據當前瀏覽器(
chrome 71.0.3578.98(正式版本) (64 位)),加上自己的理解,每個例子都是親測過

這篇博文主要分爲以下幾個部分:

margin--基礎知識
margin--在同級元素(非父子關係)之間應用
margin--在父元素和子元素之間應用(重點)
margin--margin值的單位爲%時的幾種情況

第一部分:margin--基礎知識

  要介紹margin的基礎知識,我們不可迴避地要談到css盒子模型(Box Model),一般而言,css盒子模型是用來設計和佈局的。它本質上是一個盒子,包括:外邊距(margin)、邊框(border)、內邊距(padding)以及最中間的內容(content)。下圖即爲盒子模型(這裏只談W3C規範的標準盒模型,而不談IE5和IE6在怪異模式中使用的非標準的盒子模型):

clipboard.png

   我們要介紹的margin在最外層,因爲margin(外邊距)一定是透明的,所以它可以用來使得不同的盒子之間留有一定的間隙從而達到佈局美觀等效果。從上面的盒子模型中我們可以看到,margin在四周均存在,我們可以使用margin-top、margin-right、margin-bottom、margin-left分別設置這四個方向的margin值。(注:由於這部分知識較爲基礎,所以我不再在這部分不做更多介紹)

第二部分:margin--在同級元素(非父子關係)之間應用

  這一部分主要介紹水平方向和豎直方向的外邊距的合併問題。

 ####(1)水平方向的外邊距合併
  兩個水平方向的盒子相遇,那麼最終兩者之間的距離爲左邊盒子的右外邊距和右邊盒子的做外邊距之和。

例1:代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>水平方向的兩個盒子</title>
    <style>
        *{
            margin:0;
            padding:0;
            border:0;
        }
        body{
            font-size: 0;
        }
        .left{
            width: 100px;
            height: 100px;
            background: red;
            display: inline-block;
            margin-right: 50px;
            font-size: 20px;
        }
        .right{
            width: 100px;
            height: 100px;
            background: yellow;
            display: inline-block;
            margin-left: 50px;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div class="left">寬爲100px,右邊距爲50px</div>
    <div class="right">寬爲100px,左邊距爲50px</div>
</body>
</html>

效果如下:

clipboard.png

這時兩者之間的距離剛好爲100px。

補充說明:大家可以看到,爲了使得兩個div(塊狀元素)脫離正常的文檔流我使用了display:inline-block;屬性,另外,我還把body的font-size設置爲0,這樣可以解決inline-block自身的問題(如果不清楚這裏的描述可以看我的博文《理解與應用css中的display屬性》,這篇文章介紹了inline-block存在的問題),否則兩個div的舉例會大於100px。當然使用float也可以使得兩個div出現在同一行中。

####(2)豎直方向的外邊距合併
  兩個豎直方向的盒子相遇時,其豎直方向的距離等於上方盒子的下外邊距和下方盒子的上外邊距中較大的一個。

  例2:代碼如下:

 `
<head>

<meta charset="UTF-8">
<title>水平方向的兩個盒子</title>
<style>

    .top{
        width: 100px;
        height: 100px;
        margin-bottom: 100px;
        background: red;
    }
    .bottom{
        width: 100px;
        height: 100px;
        margin-top: 50px;
        background: green;
    }
</style>

</head>
<body>

<div class="top">高爲100px,下邊距爲100px</div>
<div class="bottom">高爲100px,上邊距爲50px</div>

</body>
</html>

  效果如下:


![clipboard.png](/img/bVbnQFi)


**這時我們肉眼都可以觀察出來,兩者豎直方向的舉例大約爲100px(實際就是100px)而非100+50=150px;這正是因爲兩個豎直方向的盒子相遇時,其豎直方向的距離等於上方盒子的下外邊距和下方盒子的上外邊距中較大的一個。**

  另外一個有趣的例子就是:假設有一個元素同時設置了margin-top和margin-bottom,但是內容爲空,那麼這兩個margin值也會疊加,值爲兩者最大的一個,它類似與豎直方向上兩個盒子margin值的疊加。代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="UTF-8">
<title>水平方向的兩個盒子</title>
<style>

    .top{
        width: 500px;
        height: 100px;
        background: red;
    }
    .middle{
        margin-top: 100px;
        margin-bottom:50px;
    }
    .footer{
        width: 500px;
        height: 100px;
        background: green;
    }

</style>

</head>
<body>

<div class="top">上面的div,高100px</div>
<div class="middle"></div>
<div class="footer">下面的div,高100px</div>

</body>
</html>

  最終的效果如下:


![clipboard.png](/img/bVbnQFs)


  **我們發現這時在上面的div和在下面的div之間的舉例並不是100+50=150px,而是兩者中的最大者,即100px。**

  
  那麼W3C爲什麼會設定這樣的標準而不設定和水平方向一樣的標準呢?即margin值的疊加,實際上這也是有一定的道理的。比如我們需要設計一個由若干個段落構成的一個頁面。我們需要設置margin-top和margin-bottom使得第一段和頁面的最上方有一段距離,使得最後一段和最下方有一段距離。下面是不疊加和疊加的效果圖:

![clipboard.png](/img/bVbnQFM)

我們可以看到左邊的頁面沒有重疊,那麼兩個段落之間的舉例就是最上方的兩倍間距了,而右邊的頁面發生了重疊,則所有的間距都是相等的。或許這就是這樣設定標準的目的吧,誰知道呢?

###第三部分:margin--在父元素和子元素之間應用(重點)
    第二部分介紹了同級元素之間使用margin,而這一部分將要介紹最有意思的父元素和子元素之間margin的應用。這一部分,我們同樣從兩個方面來討論。一方面是子元素設置水平方向上的margin值,另一方面是子元素設置豎直方向的margin值。

####(1)在子元素中設置水平方向的margin值
  我們可以設置margin-left來控制子元素的左邊框和父元素的左邊框之間的舉例。
  例3:

<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="UTF-8">
<title>margin</title>
<style>
    *{padding:0; margin:0; border:0;}
    .father{
        width: 500px;
        height: 500px;
        background: red;
    }
    .son{
        width: 100px;
        height: 100px;
        background: green;
        margin-left: 100px;
    }
</style>

</head>
<body>

<div class="father">
    <div class="son">寬度爲100px,margin-left爲100px。</div>
</div>

</body>
</html>

我將子元素的margin-left設置爲了100px;效果如下:

![clipboard.png](/img/bVbnQFU)


即子元素的左邊框和父元素的左邊框之間的距離爲100px。與在同級元素之間設置margin不同,因爲同級元素之間的margin不會考慮到padding,但是在父元素和子元素就不同了,那麼如果父元素中如果有padding,效果會是什麼樣的呢?請看下面一個例子:

例4:下面我們在上面例子的基礎上給父元素添加padding值。

<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="UTF-8">
<title>margin</title>
<style>
    *{padding:0; margin:0; border:0;}
    .father{
        width: 500px;
        height: 500px;
        padding:100px;
        background: red;
    }
    .son{
        width: 100px;
        height: 100px;
        background: green;
        margin-left: 100px;
    }
</style>

</head>
<body>

<div class="father">
    <div class="son">寬度爲100px,margin-left爲100px。</div>
</div>

</body>
</html>
 `
上面的代碼給父元素添加了100px的padding值,效果如下:
clipboard.png

我們可以看到子元素舉例上方的距離爲100px,因爲子元素一定是在父元素的content的部分的,這點毫無疑問。

但是經過測量可以發現子元素的左邊框距離父元素的左邊框之間的距離爲200px,因爲其中還有100px的左padding值,前面的例子因爲我沒有設置padding值,所以沒有觀察出來,因此這就說明了在子元素中設置margin-left,其值實際上是子元素的左邊框距離父元素左padding內側的距離。

 例5:margin-right的使用和margin-left的使用是相似的,我在這裏只舉一個例子。

  這個例子在子元素中設置了margin-right值,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>margin</title>
    <style>
        *{padding:0; margin:0; border:0;}
        .father{
            width: 500px;
            height: 500px;
            padding:100px;
            background: red;
        }
        .son{
            float: right;
            width: 100px;
            height: 100px;
            background: green;
            margin-right: 100px;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="son">寬度爲100px,margin-right爲100px。</div>
    </div>
</body>
</html>

這個例子與例4的區別僅在與子元素的位置不同。效果如下:

clipboard.png

通過這個例子可以說明margin-right的值是子元素的右邊框和父元素的右padding內側的距離。只是前面的幾個例子我沒有使用padding,所以無法觀察出來。

(2)在子元素中設置豎直方向的margin值

 按照前面的經驗,理論上來說,我們同樣可以通過設置margin-top的值使得子元素的上邊框和父元素的上padding的內側留有一定的距離。那麼我們就試試吧!
  例6:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>margin</title>
    <style>
        *{padding:0; margin:0; border:0;}
        .father{
            width: 500px;
            height: 500px;
            background: red;
        }
        .son{
            width: 100px;
            height: 100px;
            background: green;
            margin-top: 100px;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="son">高度爲100px,margin-top爲100px。</div>
    </div>
</body>
</html>

  這個例子我設置了margin-top爲100px,效果如下:

這並不是我們想要的效果啊,我們希望子元素的上部距離父元素的上部爲100px,可是我們看到的卻是父元素的上部距離瀏覽器頁面的上部有100px的距離,這是爲什麼呢?哪裏出現問題了呢?

clipboard.png

  實際上這是因爲當父元素沒有設置padding值以及border值時,出現了一個bug--父元素的上方與子元素的上方完全重合在了一起,無法分開。所以纔會導致上述這種父元素和子元素同時向下的情況。

對於這種問題解決方法有下面幾種:

方法一:給父元素添加padding-top值
方法二:給父元素添加border值
方法三:給父元素添加屬性overflow:hidden,或者overflow:auto;
方法四:給父元素或者子元素聲明浮動float
方法五:使父元素或子元素聲明爲絕對定位:position:absolute;

方法一:基於例6,在父元素的css代碼中添加padding-top:1px;方法的唯一缺點就是增加了1px的誤差。

方法二:基於例6,在父元素的css代碼中添加border-top:1px solid transparent;同樣達到了效果, 缺點同方法一。

方法三:基於例6,在父元素的css代碼中添加overflow:hidden;
同樣達到了效果,並且沒有任何誤差的存在。堪稱perfect!!!!

方法四:給父元素或者子元素聲明float;基於例6,在子元素css代碼添加float:left;或者在父元素css代碼添加float:left;均達到效果,優點:沒有像素的誤差。 缺點:float有時是不必要的。

方法五:給父元素或者子元素添加position:absolute;屬性。 同樣達到效果。
優點:同方法四。 且只要我們不使用top和left也不會有任何影響,所以這也是一種不錯的方法。

上述方法三、四、五實際上都是去除子元素margin穿透父容器的方法,可以歸類爲bfc法,本質相同。

第四部分:margin值的單位爲%時的幾種情況

 之前我舉例子時使用margin,它的值都是以px爲單位的,這個理解起來沒有問題。但是如果margin值是以%爲單位呢?實際上這時候百分比(%)是相對於該元素的父元素(容器),對於同級元素和父子元素都是如此。(再次感謝 博友@小精靈Pawn 提供的建議!!基於此建議補充這部分內容) 但是在同級元素中使用豎直方向的margin時會出現意想不到的結果,下面舉例說明。

(1)同級元素在水平方向使用值爲%的margin

  例7:

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>margin</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        .first{
            float: left;
            width: 200px;
            height: 200px;
            background: green;
        }
        .second{
            float: left;
            width: 200px;
            height: 200px;
            background: red;
            margin-left: 20%;
        }
    </style>
</head>
<body>
    <div class="first">寬爲200,無margin</div>
    <div class="second">寬爲200,margin-left爲20%;</div>
</body>
</html>

這個例子中,設置兩個元素向左浮動,以便於觀察兩者水平方向的margin。其中左邊div無margin,右邊div的margin-left爲20%,效果如下:

clipboard.png

從效果圖可以看出兩個div之間的間距始終爲父元素(這裏右邊div的父元素即爲body,其寬度爲瀏覽器寬度)的20%。

(2)同級元素在豎直方向使用值爲%的margin

   根據例7的啓發,我們可以猜想,如果在豎直方向上使用margin,且值的單位爲%,那麼最終兩者之間的距離將是父元素(上例中爲body)的百分數。那麼究竟是不是這樣呢?看下面的例子。

例8

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>margin</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        .first{
            width: 200px;
            height: 200px;
            background: green;
        }
        .second{
            width: 200px;
            height: 200px;
            background: red;
            margin-top: 10%;
        }
    </style>
</head>
<body>
    <div class="first">高爲200,無margin</div>
    <div class="second">高爲200,margin-top爲20%;</div>
</body>
</html>

這裏設置上面的div無margin,下面的div的margin-top爲10。
我們發現,當我在縮小瀏覽器的高度時,豎直方向上的間距並沒有縮小!!! 而當我縮小瀏覽器的寬度時,豎直方向上的距離縮小了!!!

這就說明:統計元素之間在豎直方向上使用margin,當值的單位爲%時,它是相對於父元素的寬度。

  那麼這裏爲什麼不是如我們所希望的那樣相對於瀏覽器的高度呢?知乎上有大神是這樣解釋的(原文地址:https://www.zhihu.com/questio...):

clipboard.png

(3)父子元素使用值爲%的margin

  對於父子元素,如果在子元素中使用單位爲%margin,那麼這個margin值是相對於父元素的寬度和高度的。

例9 代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        .father{
            width: 500px;
            height: 300px;
            background: red;
            overflow: hidden;
        }
        .son{
            width: 100px;
            height: 100px;
            background: green;
            margin-top: 20%;
            margin-left: 20%;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="son"></div>
    </div>
</body>
</html>

在這個例子中,我設置了margin-left的值爲20%,margin-top的值爲20%,父元素的width爲500px,父元素的height爲300px。下面看看效果吧。

從上圖可以看出子元素的margin-top值最終同樣是
clipboard.png

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章