CSS艺术之---负margin之美

CSS中负边距(nagative margin)是布局中常用的一个技巧,只要运用得当时常会产生奇妙的效果,勘称CSS中的奇淫巧计,很多CSS布局方法都依赖于负边距,掌握它对于前端童鞋来说还是非常重要的。

一、原理

文档流

百度百科中的定义:文档流是文档中可显示对象在排列时所占用的位置。将窗体自上而下分成一行行, 并在每行中按从左至右的顺序排放元素,即为文档流。(自己的理解是从头到尾按照文档的顺序,该在什么位置就在什么位置,也可以按照上面的意思理解,自上而下,自左到右的顺序)

那些没有脱离文档流的元素(指不是浮动元素也不是绝对定位、固定定位的元素等),其在页面中的位置是跟随者文档流的变化而变化的。看下面这幅图:

这里写图片描述

负边距对这些由文档流控制的元素的作用是,会使它们在文档流中的位置发生偏移,但这种偏移不同于相对定位,通过相对定位偏移后,其仍然会坚守着它原来占据的空间,不会让文档流的其它元素乘虚而入。而通过负边距进行偏移的元素,它会放弃偏移前占据的空间,这样它后面文档流中的其它元素就会“流”过来填充这部分空间。还是通过例子来说明吧。现在我们把上图中的块状元素、行内元素以及inline-block元素都设一个负边距 margin:-10px; 看看会发生什么:

这里写图片描述

具体发生了什么变化自己体会体会,负的边距好像能减小元素在文档流中的尺寸一样,但事实上,它的尺寸大小并没变,只是文档流在计算元素位置的时候,会认为负边距把元素的尺寸减小了,因此位置也就发生变化了。
所以,一切只要是由文档流决定的东西,负边距就能起作用了。

总之一句话,在文档流中,元素的最终边界是由margin决定的,margin为负的时候就相当于元素的边界向里收,文档流认的只是这个边界,不会管你实际的尺寸是多少。

负边距对元素宽度的影响

负边距不仅能影响元素在文档流中的位置,还能增加元素的宽度!这个作用能实现的前提是:该元素没有设定width属性(当然width:auto是可以的)。
比如下图的绿色部分是一个块状元素,它没有设定宽度。它被包裹在一个宽度为400px,且水平居中的父元素中。

这里写图片描述

现在给这个元素的设一个margin-right:-100px;

这里写图片描述

我们看到它的宽度的确变长100px;然后再给它设一个margin-left:-100px;

这里写图片描述

我们看到它变得更宽了。
怎么理解呢?子块状元素的宽度设置为width:auto;或者不设置(默认width:auto;)的时候,是会根据其margin边界来填充父元素的,若正常设置为margin:100px;那么子元素的宽度必然减小200px;反之若设置margin:-100px;那么其为了正常填充整个父元素其宽度需要增加200px。

二、应用

1、左右列固定,中间列自适应布局

此例适用于左右栏宽度固定,中间栏宽度自适应的布局。由于网页的主体部分一般在中间,很多网页都需要中间列优先加载,而这种布局刚好满足此需求。

CSS:

    body{
        margin: 0;
        padding: 0;
        min-width: 600px;
    }
    .container{
        width: 100%;
        float: left;
    }
    .main{
        margin: 0 210px;
        background-color: #1B6540;
        height: 200px;
    }
    .left,.right{
        float: left;
        width: 200px;
        height: 200px;
        background-color: #4FA46B;
    }
    .left{
        margin-left: -100%;
    }
    .right{
        margin-left: -200px;
    }

HTML:

    <div class="container">
        <div class="main">
            main
        </div>
    </div>
    <div class="left">
        left
    </div>
    <div class="right">
        right
    </div>

效果:

这里写图片描述

2、去掉列表右边框

项目中经常会使用浮动列表展示信息,为了美观通常为每个列表之间设置一定的间距(margin-right),当父元素的宽度固定式,每一行的最右端的li元素的右边距就多余了,去除的方法通常是为最右端的li添加class,设置margin-right:0; 这种方法需要动态判断为哪些li元素添加class,麻烦!!!利用负margin就可以实现下面这种效果:

CSS:

    *{
        padding: 0;
        margin: 0;
    }
    ul,li{
        list-style: none;
    }
    .test{
        width: 320px;
        margin: 20px auto;
        background-color: #1B6540;
    }
    .test ul{
        margin-right: -10px;
    }
    .test ul li{
        float: left;
        width: 100px;
        height: 100px;
        background-color: #4FA46B;
        margin-right: 10px;
        margin-bottom: 10px;
    }
    .clearfix:after{
        content: "";
        height: 0;
        display: block;
        clear: both;
    }

HTML:

    <div class="test clearfix">
        <ul>
           <li>子元素1</li> 
           <li>子元素2</li> 
           <li>子元素3</li> 
           <li>子元素4</li> 
           <li>子元素5</li> 
           <li>子元素6</li> 
        </ul>
    </div>

效果:

这里写图片描述

3、负边距配合绝对定位水平垂直居中

这个前提条件是已知子元素的宽高。

这里写图片描述

CSS:

    .container{
        width: 500px;
        height: 500px;
        margin: 20px auto;
        background-color: #1B6540;
        position: relative;
    }
    .inner{
        width: 200px;
        height: 200px;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        background-color: #4FA46B;
    }

HTML:

    <div class="container">
        <div class="inner">

        </div>
    </div>

4、多列等高

此例关键是给每个框设置大的底部内边距,然后用数值相似的负外边距消除这个高度。这会导致每一列溢出容器元素,如果把外包容器的overflow属性设为hidden,列就在最高点被裁切。
CSS:

    *{
        padding: 0;
        margin: 0;
    }
    .container{
        overflow: hidden;
        width: 500px;
        margin: 20px auto;
    }
    .left,.mid,.right{
        margin-bottom: -200px;
        padding-bottom: 200px;
    }
    .left {
        float: left;
        width:  100px;
        background: #4FA46B;
    }
    .mid {
        float: left;
        width: 300px;
        background: #1B6540;
    }
    .right {
        float: right;
        width: 100px;
        background: #4FA46B;
    }
    p {color: #FFF;text-align: center}

HTML:

    <div class="container">
        <div class="left">
            <p style="height:50px">height:50px</p>
        </div>
        <div class="mid">
            <p style="height:100px">height:100px</p>
        </div>
        <div class="right">
            <p style="height:200px">height:200px</p>
        </div>
    </div>

效果:

这里写图片描述

5、去除列表最后一个li元素的border-bottom

列表中我们经常会添加border-bottom值,最后一个li的border-bottom往往会与外边框重合,视觉上不雅观,往往要移除。

CSS:

    *{padding: 0;margin: 0;}
    ul,li{list-style: none;}
    .container{
        width: 500px;
        margin: 20px auto;
        background-color: #84D0AA;
        border: 3px solid #FF6798;
        z-index: 999;
        overflow: hidden;
    }
    ul li{
        height: 30px;
        line-height: 30px;
        border-bottom: 1px dotted #fff;
        padding: 5px;
        margin-bottom: -1px;
    }

HTML:

    <div class="container">
        <ul>
            <li>Test</li>
            <li>Test</li>
            <li>Test</li>
            <li>Test</li>
            <li>Test</li>
        </ul>
    </div>

效果:

这里写图片描述

注意:其中具有边框的父元素如果不加overflow:hidden;会导致出现边框与子元素li标签的边框重叠的情况,如下:

这里写图片描述

我相信这个微小的瑕疵会逼死无数像我这样的强迫症患者..

详细资源可以参考:The Definitive Guide to Using Negative Margins
有什么好的问题或者资源欢迎补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值