负外边距
这两天的主要精力在完成 baidu-ife 的 task0001,其中涉及到负外边距的知识和实战。虽然平时关于这方面接触的不多,但好在网上、书上的资料比较丰富,就趁着这个机会总结整理一下。
基础知识
抄书、粘贴复制也没意思,贴上几篇博文。
CSS 布局奇淫巧计之-强大的负边距,这篇文章从“负边距在普通文档流中的作用和效果”、“左和右的负边距对元素宽度的影响”、“负边距对浮动元素的影响”、“负边距对绝对定位元素的影响”这四个方面讲解,浅显易懂。
由浅入深漫谈 margin 属性,这个讲的深。
我知道你不知道的负 Margin,这个偏实战。
负值之美:负值在页面布局中的应用,这个也偏实战。
布局
三列布局,其中左侧和右侧的部分宽度固定,中间部分宽度随浏览器宽度的变化而自适应变化(双飞翼布局)。
<div class="wrapper">
  <div class="main">
    <div class="content">
      <h1>main方法一</h1>
    </div>
  </div>
  <div class="sub">
    <h1>sub</h1>
  </div>
  <div class="extra">
    <h1>extra</h1>
  </div>
</div>
div.containerFirst div.wrapper {
    height: 200px;
    text-align: center;
}
div.containerFirst div.main {
    float: left;
    width: 100%;
    height: 200px;
    background-color: #3F5057;
}
div.containerFirst div.main div.content {
    height: 200px;
    margin: 0 190px;
    color: white;
}
div.containerFirst div.sub {
  float: left;
  width: 190px;
  height: 200px;
  margin-left: -100%;
  background-color: #C6D38E;
}
div.containerFirst div.extra {
  float: left;
  width: 190px;
  height: 200px;
  margin-left: -190px;
  background-color: #A1C5BB;
}
利用负边距对 浮动元素 的影响。将 div.sub 和 div.extra 放置在浏览器两侧。而 main 内部增加一个 div.content ,设置其 margin-left 、 margin-right 的值分别为 div.sub 和 div.extra 的宽度。这样做的目的是使 div.content 里的内容正常显示,而不会跑到 div.sub 内。
两列布局,其中左侧部分宽度固定、右侧部分宽度随浏览器宽度的变化而自适应变化
<div class="wrapperFirst">
  <div class="aside">
    <h1>aside</h1>
  </div>
  <div class="main">
    <div class="content">
      <h1>main</h1>
    </div>
  </div>
</div>
div.wrapperFirst div.aside {
  float: left;
  width: 360px;
  height: 300px;
  background-color: #C9EFBA;
}
div.wrapperFirst div.main {
  width: 100%;
  height: 300px;
  margin-right: -360px;
  background-color: #F5D999;
}
利用负边距对 浮动元素 的影响。
知乎采取的便是这样的布局,不过对 div.wrapper 增加了最大宽度。
三栏等高布局
<div class="wrapper">
  <div class="box">
  </div>
  <div class="box">
  </div>
  <div class="box">
  </div>
</div>
* {
  padding: 0px;
  margin: 0px;
}
div.wrapper {
  width: 100%;
  overflow: hidden;
}
div.box {
  width: 250px;
  padding-left: 20px;
  padding-right: 20px;
  padding-top: 20px;
  padding-bottom: 520px;
  margin-bottom: -500px;
  margin-left: 20px;
  float: left;
  display: inline-block;
  color: white;
  background-color: #0767c8;
}
把列的 padding-bottom 设为较大的值(因为不知道最长列与最短列之间的差值有多少),用来抵消 margin-bottom 负值带来的内容移动。最后配合 div.wrapper 的 overflow:hidden ,拦腰截断最长列,三栏等高布局。
定位
水平垂直居中
<div class="wrapper">
  <div class="inner">
  </div>
</div>
div.wrapper {
  position: relative;
  height: 500px;
  width: 500px;
  margin: 0 auto;
  background-color: black;
}
div.inner {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 300px;
  height: 300px;
  margin-left: -150px; /*  宽度的一半 */
  margin-top: -150px;  /* 高度的一半 */
  background-color: white;
}
用绝对定位将 div.inner 的定点定位到 div.wrapper 的中心,然后设置 div.inner 的 margin-top 、 margin-left 的负值,将其拉回中心,最后达到水平居中的效果。
除去列表右边距
<div class="wrapper clear">
  <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</div>
* {
  padding: 0px;
  margin: 0px;
}
div.wrapper {
  width: 590px;
  margin: 20px auto;
  border:1px solid #0767c8;
  overflow: hidden;
}
div.wrapper.minus ul {
  margin-right: -10px;
}
div.wrapper li {
  float: left;
  display: inline-block;
  width: 90px;
  height: 90px;
  margin-bottom: 10px;
  margin-right: 10px;
  background-color: #0767c8;
}
.clear:after {
  content: " ";
  display: table;
  clear:both;
}
利用负边距对 元素宽度 的影响。为 ul 设置负右外边距,增加其宽度,让 li 能够恰好排列切最后一个右外边距超出 div.wrapper 的边框,配合 overflow:hidden ,达到消除列表右边距的效果
类似的用法还有3.去除列表最后一个 li 元素的 border-bottom。同样也是:增加(marin-bottom 负值)-超出-hidden
其他收获
- 
    
实现“两列布局,其中左侧部分宽度固定、右侧部分宽度随浏览器宽度的变化而自适应变化”有很多方法。请点击 DEMO
虽然看起来很乱,但是这几个方法其实就涉及到两点:一个是如何使
aside在预定位置,一个是aside在预定位置的情况下,使得main的内容正常显示。前者可以使用浮动、绝对定位,后者可以对main使用负边距,还是content使用margin-left。 - 
    
《CSS权威指南》中提到:对于一个正常流中的块级元素,其水平部分综合就等于父元素的 width。也就是说,
margin-left、border-left、padding-left、width、padding-right、border-right、margin-right这 7 个属性的值加在一起必须是元素包含块的宽度。在这 7 个属性中,只有 3 个属性可以设置为
auto、元素内容的width,以及左右外边距。 
以上。