CSS 盒模型

所有文档元素都生成一个矩形框,这称为元素框(element box),它描述了一个元素在文档布局中所占的空间大小。而且,每个框影响着其他元素框的位置和大小。

网页布局中,我们是如何把里面的文字、图片等内容,按照美工给我们的效果图排列的整齐有序呢?

简单来说,网页布局的本质就是盒模型摆放的过程。


盒模型的组成

所谓盒模型就是把 HTML 页面中的元素看作是一个矩形的盒子,也就是一个盛放内容的容器。每个矩形都是由元素的内容、内边距(padding)、边框(border)和外边距(margin)组成。

[ 盒子的计算尺寸 ]

大多数浏览器,如 Firefox、IE6+ 都采用了 W3C 规范,符合 CSS 规范的盒模型的总宽度和总高度的计算规则为:

// 外盒尺寸计算(元素空间尺寸)
   
   Element空间高度 = content height + padding + border + margin
   Element空间宽度 = content width + padding + border + margin

// 内盒尺寸计算(元素大小)

   Element Height = content height + padding + border     // Height为内容高度
   Element Width  = content width + padding + border      // Width为内容高度

// 注意:width属性和height属性仅适用于块级元素,对行级元素无效(img和input除外);
// 计算盒模型的总高度时,还应考虑上下两个盒子垂直外边距合并的情况。
// 如果一个盒子[ 没有给定宽度/高度或继承父元素的宽度/高度(本质上也没有给定宽度或高度) ],则padding不会影响盒子的大小。
   例:<div>Hello World!</div>       // 默认宽度为100%,padding左右后仍然为100%;
       <style>
          height:30px;
          border:1px solid red;
          padding-left:30px;
          /*width:100%;*/   // 如果加上了width:100%,padding左右后,宽度为100%+30px,产生了影响。
       </style>

[ 盒模型布局的稳定性 ] 刚接触盒模型时,可能最大的困惑是:分不清内外边距的使用。即,什么情况下使用内边距,什么情况下使用外边距?— 其实,它们在大部分情况下是可以混用的,也就是说觉得哪个方便用哪个。

当然,从稳定性的角度考虑,建议:优先使用 width(宽度)> padding(内边距)> margin(外边距)。因为:

  • margin 可能发生外边距合并的现象,且在 IE6 下存在 margin 加倍的 bug(讨厌),所以,最后使用;
  • padding 会影响盒子大小,需要进行加减运算(麻烦),所以,其次使用;
  • width 没有问题,可以使用宽度剩余法或高度剩余法来实现布局,所以,优先推荐使用。

[1] content(内容区)                                                        // { CSS3自适应宽高?↓}

[ 宽高 ]内容区由width(宽度)、height(高度)两个属性设置,content = width * height 。           

width被定义为从左内边界到右内边界的距离,height被定义为从上内边界到下内边界的距离。

[ 怪异盒模型 ] IE6-浏览器的宽高定义的是可见元素框的尺寸,而不是元素框的内容区尺寸。

width:<length> | <percentage> | auto | inherit        默认值为auto,浏览器根据不同的情况设定
      引申:max-width、min-width
height:<length> | <percentage> | auto | inherit       默认值为auto,内容高度

// 宽高和margin可以设置auto。
// 对于块级元素来说,宽度设置为auto,则会尽可能的宽;如果没有显式声明包含块的height,则元素的百分数高度会重置为auto。

[ 最大最小宽高 ] 

设置最大最小宽高的好处是可相对安全地混合使用不同的单位;使用百分数的同时,也可设置基于长度的限制。

min-width | min-height    // 初始值: 0
  值: <length> | <percentage> | inherit
 
max-width | max-height    // 初始值: none
  值: <length> | <percentage> | inherit
 
[注意] IE6-浏览器不支持min-width | min-height | max-width | max-height
[注意] 当最小宽度(高度)大于最大宽度(高度)时,以最小宽高的值为准。

[2] 内边距 padding                                                   // 兼容性问题?!

padding属性用于设置内边距,即设置边框与内容之间的距离。对于行内元素,左内边距应用到元素的开始处,右内边距应用到元素的结尾处,垂直内边距不影响行高,但会影响自身尺寸,加背景颜色可以看出。

padding:[<length> | <percentage>]{1,4} | inherit              // 百分数,相对于包含块的width

值缩写:TRBL                   // 对面相等,后者省略;四面相等,只设一个;内边距不能为负值。

如, padding:40px 30px 20px 10px;
    padding:20px;
    padding:20px 10px;
    padding:30px 10px 20px;

[3] 外边距 margin                                                         { margin负值、重叠、auto和无效情形?↓ }

margin 用于设置外边距。设置外边距会在元素之间创建“空白”,这段空白通常不能放置其他内容。

margin:[<length> | <percentage> | auto]{1,4} | inherit
 
四值顺序:TRBL
【1个值】margin: top | right | bottom | left;
【2个值】margin: top | bottom  left | right;
【3个值】margin: top left | right bottom;
【4个值】margin: top right bottom left;

[ 妙用 - 水平居中 ] margin:0 auto;

外边距可以让一个盒子实现水平居中,需要满足以下两个条件:
  1. 必须是块级元素;
  2. 盒子必须指定了宽度(width);
然后,给左右外边距都设置auto,就可以实现块级元素的水平居中。

例:.demo{ width:1200px;margin:0 auto; }

[ CSSRset - 清除元素的默认边距 ] 为了更方便的控制网页中的元素,制作网页时,须清除元素默认的内外边距:

* { padding:0;margin:0; }

// 另,外边距可以应用到行内元素,但行内元素是只有左右内外边距的,没有上下内外边距,
// 也就是说,上下外边距对行高没有任何影响。

[ 现象 - margin合并 ] 使用 margin 定义块级元素的垂直外边距时,可能会出现外边距的合并。

  • 相邻块元素垂直外边距的合并 — 毗邻元素垂直重叠会取最大值              // 解决方案:避免就好了

当上下相邻的两个块元素相遇时,如果上面的元素有下边距margin-bottom,下面的元素有上外边距margin-top,则它们之间的垂直间距不是margin-bottom与margin-top之和,而是两者中的较大值,这种现象被称为相邻块元素垂直外边距的合并(也称为外边距塌陷)。

  • 嵌套块元素垂直外边距的合并 — 父元素与第一个 / 最后 一个子元素会合并

对于两个嵌套关系的块元素,如果父元素没有上内边距及边框,则父元素的上外边距会与子元素的上外边距发生合并;合并后的外边距为两者中的较大者,即是父元素的上外边距为0,也会发生合并。

解决方案:可以为父元素定义 1px 的上边框或上内边距 或 可以为父元素添加 overflow:hidden 。


[4] 边框 border                                               { 深入了解border?↓ }

元素外边距内就是元素的边框 border,元素的边框是围绕元素内容的内边距的一条或多条线。

border: [ <border-width> || <border-style> || <border-color> ] | inherit
      // 边框由粗细、样式和颜色三部分组成
         border-width:[<length> | thin | medium | thick]{1,4} | inherit
         border-style:[solid | dashed | dotted | …]{1,4} | inherit     // 默认没有边框
         border-color:[color | transparent]{1,4} | inherit           // 默认为字体颜色

例,border:1px solid blue;
    border-width:0 1px 2px 3px;
    border-style:solid;
    border-color:#ff0000;

[ 行内元素 ] 对于行内元素,边框实际上画在各行之外的下一个像素上,由于各行紧挨着,所以其边框会重叠。无论为行内元素的边框设置怎样的宽度,不会对行高有任何影响;但左右边框会分别显示在元素的开始处和结尾处。

[ 表格的细线边框 ]            // border-collapse:collapse; 表示边框合在一起。

table { border-collapse: collapse; }
td { border: 1px solid blue; }

[ 圆角边框 ] border-radius 可以为边框设置圆角(IE8-不支持),四值顺序是:左上、右上、右下、左下。

border-radius: none(默认)
border-radius: <length>{1,4}[/<length>{1,4}]?
如果反斜杠存在,前面的值是水平方向的半径,后面的值是垂直方向的半径;如果没有则水平和垂直方向相等。

溢出及相关

[1] overflow(溢出)                                                               引申:overflow-x | overflow-y?↓ }

设置盒子里的内容超出时如何设置。当一个元素固定为某个特定大小,但内容在元素中放不下,此时就可以利用overflow属性来控制这种情况。

overflow:visible | hidden | scroll | auto

// visible 可视; hidden 隐藏;scroll 一直显示滚动条;auto 内容少时无,超出时显示滚动条;

 [2] 裁剪 clip

CSS裁剪clip这个属性平时用的不多,但其实它并不是CSS3的新属性,很早就开始出现了。

一个绝对定位或固定定位元素通过使用属性clip可以改变剪裁区域的形状,但并不改变元素本身的宽高属性。

值: rect(top,right,bottom,left) | auto | inherit

初始值: auto
应用于: 绝对定位或固定定位元素
[注意] 默认值auto表示元素的内容不应剪裁
// IE7-浏览器不支持rect(top,right,bottom,left),支持的写法是rect(top right bottom left);而其他浏览器两种写法都支持

clip:rect(top,right,bottom,left)中的值不是边偏移,而是距元素左上角的距离。
具体来说,就是top和bottom是表示距离元素上边界的距离;left和right是距离元素元素左边界的距离。这里元素的边界指元素边框外侧。

rect(...)的语法与CSS的其他语法相比不太一样。原因是它基于早期的定位草案,而该草案使用了左上偏移机制。

在CSS2之前,实现这个语法的IE已经成为完备推荐,于是标准从边偏移修改成适用这个实现。

但是,这意味着如果高度和宽度没有明确定义,将无法设置一致的剪裁区域。

clip:rect(...)只允许长度值和auto,不允许有百分数。

如果设置为auto,则相当于将剪裁边界设置为适当的内容边界。

对于top或left设置auto,相当于值为0;对于right或bottom设置auto,相当于值为水平方向的宽度和或垂直方向的高度和

[注意] 该元素水平方向或垂直方向的clip区域的边界是外框外侧,不包括outline

[ clip的应用 ]

1. 隐藏效果

当clip:rect(top,right,bottom,left)中的top>=bottom,或者left>=right时,可实现元素的隐藏效果,效果类似于visibility:hidden;


2. 雪碧图定位

css sprite是一种网页图片应用处理方式,它允许将一个页面涉及到的所有零星图片都包含到一张大图中,然后利用background-position来显示应该显示的区域。而如果使用clip也可以实现同样的效果。

div{
    height:128px;
    overflow: hidden;
}
img{
    position:absolute;
    background-color: rgba(0,255,0,0.5);
    clip:rect(0,auto,128px,0);
}
img:hover{
    margin-top: -128px;
    clip:rect(128px,auto,auto,0);
}
<div>
    <img src="http://7xpdkf.com1.z0.glb.clouddn.com/sofa_sprite.png" alt="测试图片">    
</div>

3. 歌词演示效果

利用clip和background-clip实现歌词演示效果,实际上通过改变宽度也可以实现,主要用于拓展思路。

@keyframes loop{
    0%{
        clip:rect(0,0px,100px,0);
    }
    100%{
        clip:rect(0,520px,100px,0);
    }
}
.show,.con{
    width: 520px;
    height: 100px;
    line-height: 100px;
    font-size: 30px;
    position:absolute;
    background-color: lightgreen;

}
.con{
    animation: loop 6s linear infinite;
    -webkit-background-clip: text;
    color: red;
}
<div class="show">我曾经跨过山和大海,也穿过人山人海</div>
<div class="con">我曾经跨过山和大海,也穿过人山人海</div>

[3] 拉伸 resize

CSS3新增了resize属性,该属性允许用户通过拖动的方式来修改元素的尺寸。本来resize应该翻译为缩放,但在实际测试中通过resize属性只可以在宽高基础上实现拉伸效果,而无法实现缩放到小于宽高的效果。

值: none | both | horizontal | vertical

none: 用户无法调整元素尺寸
both: 用户可调整元素的宽度和高度
horizontal: 用户只可调整元素的宽度
vertical: 用户只可调整元素的高度

// IE浏览器不支持resize属性。
resize与overflow关系紧密,只有当元素的overflow属性值不是visible时,resize才会起作用
因为文本框本身就具有overflow:auto的属性,所以自带resize属性

[注意] 在win7下resize拖拽区域的大小是17px*17px,实际上它就是滚动条尺寸。


[4] 滚动条

滚动条在网页中经常见到,却并没有受到足够的重视;只有当因为滚动条的问题需要处理兼容性时,才进行调试操作。


[5] 可见性 visibility                                                    { visibility:hidden & display:none?↓ }

visibility属性常见于与display属性的比较中。但实际上,该属性有自己的一些有趣的用途。

值: visible | hidden | collapse | inherit
visible:元素可见
hidden:元素不可见,但元素还是会影响文档的布局
// 可以将一个hidden元素的后代元素置为visible,这会使该后代元素正常出现
collapse:在表格中<col>或<colgroup>中使用,表示该列或列组的所有单元格不显示。如果用于非表格元素,collapse与hidden含义相同。
// webkit内核浏览器不支持给<col>或<colgroup>元素使用collapse属性。

高级特性

[1] box-sizing:设置width、height的指定区域

CSS3可通过box-sizing指定盒模型,即指定 content-box / border-box,这样计算盒子大小的方式也就发生了变化。

  • box-sizing:content-box; 盒子大小为width + padding + border,默认值,符合W3C的标准盒模型;
  • box-sizing:border-borx; 盒子大小为width,也就是说,padding和border是包含在width里面的。
box-sizing:content-box(默认) | border-box | inherit
// IE7-浏览器不支持。
// IE浏览器在getComputedStyle得到width/height是按照标准模式计算的,而不论box-sizing的取值

例,
width:150px;height:150px;padding:50px;border:5px solid blue;
box-sizing:border-box;

[ CSS盒模型 ]在CSS中,盒模型被分为两种,一种是W3C的标准模型,第二种是IE怪异盒模型。不同之处在于后者的宽高定义的是可见元素框的尺寸,而不是元素框的内容区尺寸。

目前对于浏览器大多数元素都是基于W3C标准的盒模型,但对于表单form中的部分元素还是基于IE的怪异盒模型,如input里的radio、checkbox、button等元素,如果给其设置border和padding它们也只会往元素盒内延伸。

W3C的标准模型下,宽度和高度仅仅包含了内容宽度,除去了边框和内边距两个区域,这样为web设计师处理效果带来了不少麻烦。为解决这个问题,CSS3新增了一个盒模型属性box-sizing,能够事先定义盒模型的尺寸解析方式。


[2] box-shadow 盒阴影                                                // IE8-不支持

box-shadow 可以为元素设置阴影,但需要注意的是:

  • 可以使用多重阴影,但使用过多会造成性能差。
  • 边框在内阴影之上,内阴影在背景图片之上,背景图片在背景色之上,背景色在外阴影之上。
  • 内阴影对 img 元素没有任何效果。
  • 最先写的阴影在最顶层。
  • 该属性与border-radius一脉相承,若通过border-radius设置为圆角,则box-shadow的最终呈现也将是圆角。

box-shadow:none | <shadow> [,<shadow>]*
<shadow>:insert? <length>{2,4} <color>?    
  例,box-shadow:4px 6px 3px 5px red;  

  可以简单理解为 box-shadow:inset h-shadow v-shadow blur spread color    
                           // 水平偏移 垂直偏移 模糊半径(之前内外半径个1.5px模糊) 阴影大小 颜色
                  h-shadow:必需。水平阴影的位置。允许为负值。
                  v-shadow:必需。垂直阴影的位置。允许为负值。
                  blur:可选。模糊半径。
                  spread:可选。阴影的尺寸。
                  color:可选。阴影的颜色,默认和文本颜色一致。
                  inset:可选。将外部阴影(outset)改为内部阴影。

                     多阴影(内外叠加)
                      1.外阴影 border-shadow:3px 3px 5px 2px;
                      2.内阴影 border-shadow:inset 0px 0px 5px red;

  • 模拟边框
box-shadow: 0 0 0 10px blue;
  • 单侧投影
box-shadow: 0 5px 4px -4px black;
  • 邻边投影
box-shadow: 3px 3px 6px -3px black;
  • 双侧投影
box-shadow: 5px 0 5px -5px black,-5px 0 5px -5px black;

[3] outline  轮廓                                                  { 深入了解outline?↓ }

轮廓是绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。

outline:[<outline-width> || <outline-style> || <outline-color>] | inherit
描述边框:不占空间,border外;描边,与周围环境进行区分。
// IE7-浏览器不支持

   outline-width:<length> | thin | medium | thick | inherit
   outline-style:solid | dashed | dotted | … | inherit
   outline-color:<color> | invert | inherit        // invert,执行颜色反转(逆向的颜色)

轮廓outline处在边框边界的外面,它不像边框那样参与到文档流中,因此轮廓出现或消失时不会影响文档流。

即,不会导致文档的重新显示。利用轮廓,浏览器可以合并部分轮廓,创建一个连续但非矩形的形状。

[ 取消轮廓 ] 默认地,轮廓是一个动态样式,只有元素获取到焦点或被激活时呈现。

如上图所示,当input元素获得焦点的时候,会显示出一条轮廓线...

// 此处关心的不是如何设置边框,而是如何取消边框(取消默认样式),语法为:outline:0;