理解并运用 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

双飞翼布局和圣杯布局的对比

相关文章
相关标签/搜索