理解並運用 CSS 的負 margin 值

本文樣式代碼採用 SCSS。
瀏覽器兼容性爲 IE6+。php

你的網頁中,不可能沒有使用過 margin。大多數狀況下,咱們採用的都是正數的 margin 值,可能有時候會用到負的 margin 值。在咱們的印象中,負的 margin 值就相似於瀏覽器的 hack 同樣,不被人接受。可是,本文要說明的就是,負的 margin 值並非 hack,這是正常範圍內的寫法。css

Negative values for margin properties are allowed, but there may be implementation-specific limits. —— W3Chtml

根據 W3C,margin 是可以接受負值的,只是在具體實現上有一些區別。api

那麼,設置 margin 爲負值究竟會是什麼樣的效果呢?瀏覽器

與設置正值不一樣,margin 設置負值須要根據設置的方向以及元素是否浮動以及其定位方式來判斷最終的行爲。ide

因此,具體行爲按照如下幾種狀況說明。佈局

第一種狀況:元素沒有設置浮動且沒有設置定位或者 positionstatic

若是元素沒有設置浮動而且沒有設置定位或者 position 屬性爲 static 的狀況下,對元素的 margin 設置負值會有如下的效果:post

設置的 margin 的方向爲 top 或者 leftui

當設置負值的 margin 的方向爲 top 或者 left 的時候,元素會按照設置的方向移動相應的距離。spa

好比,設置 margin-left: -100px;。 那麼,元素會往左移動 100px。對於設置 margin-top 也是同樣的道理。

設置的 margin 的方向爲 bottom 或者 right

當設置負值的 margin 的方向爲 bottom 或者 right 的時候,元素自己並不會移動,元素後面的其餘元素會往該元素的方向移動相應的距離,而且覆蓋在該元素上面。

好比,設置 margin-right: -100px;。那麼,元素自己並不會移動,後面的元素會向左移動 100px 到該元素上。對於設置 margin-bottom 也是一樣的道理。

同時,在元素不指定寬度的狀況下,若是設置 margin-left 或者 margin-right 爲負值的話,會在元素對應的方向上增長其寬度。效果就和設置 padding-left 或者 padding-right 同樣。

第二種狀況:元素沒有設置浮動且 positionrelative

若是元素沒有設置浮動,可是設置了相對定位,設置 margin 爲負值的時候,表現以下:

設置的 margin 的方向爲 top 或者 left

當設置負值的 margin 的方向爲 top 或者 left 的時候,元素也會按照設置的方向移動相應的距離。

設置的 margin 的方向爲 bottom 或者 right

當設置 margin-bottom/left 的時候,元素自己也不會移動,元素後面的其餘元素也會往該元素的方向移動相應的距離,可是,該元素會覆蓋在後面的元素上面 (固然,此處說的狀況確定是後面的元素沒有設置定位以及 z-index 的狀況)。

第三種狀況:元素沒有設置浮動且 positionabsolute

若是元素沒有設置浮動,可是設置了絕對定位,設置 margin 爲負值的時候,表現以下:

設置的 margin 的方向爲 top 或者 left

當設置負值的 margin 的方向爲 top 或者 left 的時候,元素也會按照設置的方向移動相應的距離。

設置的 margin 的方向爲 bottom 或者 right

因爲設置絕對定位的元素已經脫離了標準文檔流,因此,設置 margin-right/bottom 對後面的元素並無影響。

第四種狀況:元素設置了浮動

確定沒有既設置了浮動又設置絕對定位的狀況,那樣太荒唐了。
設置了浮動的元素,再設置 postion: relative; 的話,元素的行爲和單獨設置 float 是同樣的。

對於設置了浮動的元素,設置 margin 爲負值的時候,表現以下:

若是設置的 margin 的方向與浮動的方向相同,那麼,元素會往對應的方向移動對應的距離。

好比:

.elem {
    float: right;
    margin-right: -100px;
}複製代碼

該元素則會向右移動 100px。

若是設置 margin 的方向與浮動的方向相反,則元素自己不動,元素以前或者以後的元素會向鈣元素的方向移動相應的距離。

好比:

.elem {
    float: right;
    margin-left: -100px;
}複製代碼

位於該元素左邊的元素則會向右移動 100px,同時覆蓋在該元素上。

若是後面的元素也設置了浮動的話,咱們以一個具體的例子來講明。

<div class="container">
    <div class="left"></div>
    <div class="right"></div>
</div>複製代碼
.container {
    min-height: 300px;
    margin: 30px auto;
    overflow: hidden;
    border: 1px solid #000000;

    .left {
        float: left;
        width: 400px;
        height: 200px;
        margin-right: -300px;
        background: purple;
    }

    .right {
        float: left;
        width: 300px;
        height: 200px;
        background: #cccccc;
    }
}複製代碼

.left.right 都設置了浮動,在 .left 上設置了 margin-right: -300px;,那麼,.right 會向左移動 300px,從而覆蓋在 .left 上。這種行爲與沒有既沒有設置浮動也沒有設置定位的表現相似。


到此,咱們把設置負 margin 的各類狀況以及在各類狀況下的表現都大概瞭解了一遍。那麼,咱們真正運用到實際中會是什麼樣子呢。

半遮擋的標題

原諒我措辭很差,大概就是下圖的效果:

|center

按照通常的思想,確定是直接給 title 設置絕對定位,而後再將其調整過去。

可是,按照咱們如今所說的,其實很簡單就能實現這個效果。

這裏只寫了主要部分的代碼。

<div class="title">Hey This is title!</div>
<div class="content">Hah! This is content.</div>複製代碼
.title {
    position: relative;
    width: 200px;
    height: 60px;
    margin-bottom: -30px;
    margin-left: -20px;
    background: #000000;
}

.content {
    max-width: 800px;
    height: 400px;
    padding: 0 50px;
    background: yellow;
}複製代碼

咱們爲 title 設置了兩個 margin 的負值,分別是 margin-bottom: -30px;,以及 margin-left: -20px;

設置 margin-bottom 是爲了讓 content 向上移動,設置 margin-left 是爲了讓 title 向左移動一小段距離。

還有個須要注意的地方就是,須要給 title 設置 position: relative;,根據咱們的第二種狀況所說的,這樣,才能保證 title 覆蓋在 content 之上。

簡單的一列定寬的兩列流式佈局

根據咱們的最後一種狀況,經過設置 margin 爲負值,咱們能夠很容易的實現一列定寬的兩列流式佈局。

<div class="container">
    <div class="left"></div>
    <div class="right"></div>
</div>複製代碼
.left {
    float: left;
    width: 100%;
    height: 200px;
    margin-right: -300px;
    background: purple;
}
.right {
    float: left;
    width: 300px;
    height: 200px;
    background: #cccccc;
}複製代碼

惟一須要注意的地方就是設置了 100% 寬度的元素上的 margin 負值的絕對值必定要和定寬的元素的寬度相同。

兩邊固定,中間自適應的三列布局

這是一個很老的話題了,之前也有各類實現的方式,好比雙飛翼佈局,或者聖盃佈局。

咱們此處就以雙飛翼佈局來做示例。

先設置頁面結構:

<div class="container">
    <div class="center"></div>
    <div class="left"></div>
    <div class="right"></div>
</div>複製代碼

此處咱們沒有把 center 放在中間,具體緣由後面會解釋。

而後,咱們設置這三列都浮動:

.left,
.right,
.center {
    float: left;
    height: 500px;
}複製代碼

同時爲他們指定寬度:

.left {
    width: 300px;
    background: #000000;
}

.right {
    width: 400px;
    background: #00FFFF;
}

.center {
    width: 100%;
    background: #93c759;
}複製代碼

如今咱們要讓 left 在左邊,至關於就是讓它覆蓋在 center 的上面,因此,只須要這樣一句:

margin-left: -100%;複製代碼

同時,要讓 right 在右邊,同理,這樣設置:

margin-left: -400px;複製代碼

注意,此處的 margin 值的絕對值與 right 的寬度值相同。

其實,這樣設置,咱們的三列布局就基本完成了。

那麼,咱們爲何要把 center 放在 left 和 right 以前呢?

這個其實涉及到元素的堆疊順序的知識 (這裏就不詳細講解了,後面有時間的話專門拿一篇文章來說解吧),此處簡單說明一下。

因爲咱們的三列都設置了浮動,因此,從某種意義上說,它們三個是在同一個平面的 (至關於 z-index 相同),那麼,這裏就不能根據 CSS 來判斷堆疊順序了。因此,此處的 HTML 結構就決定了它們的堆疊順序:所謂後來居上。

咱們要讓 left 在 center 之上,因此,確定須要讓 left 元素放在 center 以前。

因此,三列布局完整的 SCSS 代碼以下:

.container {
    overflow: hidden;

    .left,
    .right,
    .center {
        float: left;
        height: 500px;
    }

    .left {
        width: 300px;
        margin-left: -100%;
        background: #000000;
    }

    .right {
        width: 400px;
        margin-left: -400px;
        background: #00FFFF;
    }

    .center {
        width: 100%;
        background: #93c759;
    }
}複製代碼

References

margin-properties | W3C

The Definitive Guide to Using Negative Margins

雙飛翼佈局和聖盃佈局的對比

相關文章
相關標籤/搜索