CSS中的盒模型

时间:2022-11-11 08:46:23

CSS的盒模型描述了一些长方形盒子,这些长方形盒子被用来表示文档树中的元素,并根据视觉格式化模型进行定位。

1. 盒子的尺寸

每个盒子都有一个content区域(比如文本、图片等)和可选的包围content区域的padding、borde、margin区域。这些区域的大小由下面定义的属性决定。下图这些区域的相互关系以及与margin、border和padding相关的术语。
CSS中的盒模型
margin、border和padding可以被拆分成top、right、bottom和left段,举例来说,上图中的"LM"就表示left margin,"RP"表示 right padding,"TB"表示top border等等。
如上四个区域(content、padding、border和margin)的周界叫做边界(edge),所以,每个盒子都有四种边界:

content edge 或者说 inner edge
content edge 包围由盒子宽度和高度决定的长方形,而这个长方形区域通常取决于元素的渲染内容。四个content边决定了盒子的content box。
padding edge
padding edge包围盒子的padding区域。如果padding的宽度为0,则padding edge与content edge相同。四个padding边决定了盒子的padding box。
border edge
border edge包围盒子的border区域。如果border的宽度为0,则border edge与padding edge相同。四个border边决定了盒子的border box。
margin edge 或者说 outer edge
margin edge包围盒子的margin区域。如果margin的宽度为0,则margin edge与border edge相同。四个margin边决定了盒子的margin box。

每个边界都可以被拆分成top,right,bottom和left边。

一个盒子的content area(content width和content height),取决于如下这些因素: 生成盒子的元素是有设置了width和height属性,盒子是否包含文本或其他盒子,盒子是否是表格等。

content,padding,border区域的背景样式有元素的background属性指定,而margin区域的背景永远是透明的。

2. margin,padding,和border的例子

这个例子展示了margin,padding和border直接如何相互影响。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
  <HEAD>
    <TITLE>Examples of margins, padding, and borders</TITLE>
    <STYLE type="text/css">
      UL { 
        background: yellow; 
        margin: 12px 12px 12px 12px;
        padding: 3px 3px 3px 3px;
                                     /* No borders set */
      }
      LI { 
        color: white;                /* text color is white */ 
        background: blue;            /* Content, padding will be blue */
        margin: 12px 12px 12px 12px;
        padding: 12px 0px 12px 12px; /* Note 0px padding right */
        list-style: none             /* no glyphs before a list item */
                                     /* No borders set */
      }
      LI.withborder {
        border-style: dashed;
        border-width: medium;        /* sets border width on all sides */
        border-color: lime;
      }
    </STYLE>
  </HEAD>
  <BODY>
    <UL>
      <LI>First element of list
      <LI class="withborder">Second element of list is
           a bit longer to illustrate wrapping.
    </UL>
  </BODY>
</HTML>

这段代码最终将会在文档树中产生一个UL元素和两个LI子元素。
下面的这两张图中,第一张图展示了上面的代码最终显示的样式。第二张图展示了UL元素的margin,padding,border之间的关系以及与它的子LI元素之间的关系。
CSS中的盒模型

说明:

  • 每个LI盒子的content width由从上到下计算而来;每个LI盒子的包含块由UL元素产生。
  • 每个LI盒子的margin box的高度由盒子的content height加上上下padding,再加上上下border,再加上上下margin计算而来。注意,LI盒子之间的竖直margin合并(collapse)了。
  • 每个LI盒子的right padding被通过padding属性设置为0。这个效果在第二张图中被很明显的展示出来。
  • LI盒子的margin是透明的,因此我们看到的是UL元素padding和content区域的背景色黄色。
  • 第二个LI元素通过border-style属性指定了虚线border。

3. 外边距属性: margin-top,margin-right,margin-bottom,margin-left和margin

外边距属性指定了一个盒子的margin区域的宽度。"margin"属性设置四个边的margin,而其他的外边距属性只指定单独一边。这些属性可以应用于所有元素,但是竖直的margin对不可替代的行内元素(non-replaced inline element)没有任何影响。
上面这些属性的取值类型如下:
<绝对数值>
采用固定的宽度
<百分比>
根据盒子的包含块的宽度来计算百分比。注意,这对margin-top和margin-bottom同样适用。如果包含块的宽度由这个元素决定,那么在CSS2.1中,结果为未定义。
auto
自动
外边距属性值可以为负,但是这可能有特定的实现限制。

margin-top,margin-right,margin-bottom和margin-left指定了盒子的上、右、下、左外边距。这些属性可以被应用于除表格显示类型(除了table-caption,table和inline-table)以外的所有元素。margin-top和margin-bottom对不可替代的行内元素不起作用。
margin属性是以上四个属性的简写,可以同时设置这四个属性。如果指定了一个值,那么应用于所有的边。如果指定了两个值,那么第一个值设置top和bottom margin,第二个值设置left和right margin。如果设置了三个值,那么第一个值设置top margin,第二个值设置left和right margin,第三个值设置bottom margin。如果设置了四个值,那么依次设置top,right,bottom和left margin。

3.1 合并margin

在CSS中,两个或多个盒子(这些盒子可能是也可能不是兄弟盒子)的相邻的margin会合并成一个单一的margin。外边距合并也叫塌陷(collapse)。

相邻的竖直margin会合并,除了:

  • 根元素的盒子的margin不合并
  • 如果有清除(clearance)的元素的top和bottom margin相邻,那么这个盒子的margin会与后面跟随紧邻的兄弟盒子的margin合并,但是合并后的margin不会与父块的bottom margin合并。

水平的margin从来不合并。

两个margin相邻,当且仅当:

  • 都属于在同一个块格式化上下文中的正常文档流中的块级盒子
  • 没有行盒子(line box),没有清除(clearance),没有padding也没有border分隔。(注意,某些零高度的行盒子会被会略,参见视觉格式化模型
  • 都属于竖直相邻的盒子的边,也就是说:
    • 一个盒子的top margin和这个盒子的第一个流内孩子盒子的top margin
    • 盒子的bottom margin和这个盒子的下一个流内兄弟盒子的top margin
    • 最后一个孩子盒子的bottom margin和它的父盒子的bottommargin(如果父盒子的高度是自动(auto)计算而来)
    • 一个盒子的top和bottom margin,前提是这个盒子没有建立新的块格式化上下文,计算出来的min-height为0,height为0或auto,没有在正常文档流中的子元素。

如果一个合并后的margin的某个子margin与一个其他的margin是相邻的,那么合并后的margin也认为与这个margin相邻。

相邻的margin可能由彼此不相邻或彼此不互为祖先后代的元素产生。
上面这句话表明:

  • 浮动盒子的margin和其他任何盒子的margin不合并,即使是浮动盒子与其流内的子盒子的margin也不合并。
  • 建立新的块格式化上下文的元素(比如浮动元素和overflow的值不是visible的元素)的margin不与他们的流内的子元素的marign合并。
  • 绝对定位的盒子的margin不合并,即使与他们的流内子盒子也不合并。
  • 行内块盒子的margin不合并,即使与他们的流内子盒子也不合并。
  • 一个流内块级盒子的bottom margin总是与它的下一个紧随着的流内块级兄弟盒子的top margin合并,除非这个兄弟盒子有清除(clearance)。
  • 流内块级元素的top margin会与它的第一个流内块级子元素的top margin合并,前提是这个盒子没有top border、top padding,并且子元素没有应用清除。
  • 一个height为auto,min-height为0的流内块级盒子的bottom margin与它的最后一个流内块级子盒子的bottom margin合并,前提是这个盒子没有bottom padding、bottom border并且子盒子的bottom margin没有与其他的应用了清除的top margin合并。
  • 一个盒子本身的margin会合并,前提是这个盒子的min-hieght属性设置为0,这个盒子没有top或bottom border,没有top或bottom padding,它的height为0或者为auto,并且它不包含任何行盒子,所有的流内子盒子的margin也合并。

当两个或多个margin合并是,合并后的margin的宽度为所有合并的宽度的最大值。如果有margin的值为负值,那么最后的合并margin绝对值值将是最大的正值扣除这个负值的所得。如果所有的margin为负,那么最后合并margin绝对值值将是0扣除最大的负值所得。

如果一个盒子的top和bottom margin相邻,那么margin可能直接穿过它。在这个情况下,元素的位置就取决于它与和它有margin合并的元素的关系:

  • 如果元素的margin与它的父元素的top margin合并,那么这个元素的top border与父元素的的相同。
  • 否则,要么元素的父元素没有参与margin合并,要么父元素只有bottom margin参与合并,那么这个元素的top border edge将与它有一个非0 bottom border时的top border edge一样。

注意,被合并穿过(collapsed through)的元素的位置对与他进行margin合并的元素位置没有任何影响,只有在给元素的子元素进行布局的时候才会参考top border edge的位置。

4. 内边距属性: padding-top, padding-right, padding-bottom, padding-left和padding

内边距属性指定了盒子的padding区域的宽度。"padding"属性设置四个边的padding,而其他四个属性设置特定边的padding。
以上属性的取值类型如下:
<绝对数值>
采用固定的宽度
<百分比>
根据盒子的包含块的宽度来计算百分比。注意,这对padding-top和padding-bottom同样适用。如果包含块的宽度由这个元素决定,那么在CSS2.1中,结果为未定义。

不像外边距属性,内边距属性的值不能为负。

padding-top,padding-right,padding-bottom,padding-left这四个属性指定了盒子的上、右、下、左边的padding,可以应用于除了table-row-group, table-header-group, table-footer-group, table-row, table-column-group and table-column以外的所有元素。

padding是上面四个属性的简写形式,如果指定了一个值,那么应用于所有的边。如果指定了两个值,那么第一个值设置top和bottom padding,第二个值设置left和right padding。如果设置了三个值,那么第一个值设置top padding,第二个值设置left和right padding,第三个值设置bottom padding。如果设置了四个值,那么依次设置top,right,bottom和left padding。

5. 边框属性

边框属性指定了盒子的border area的宽度、颜色和样式。这些属性可以应用于任何元素。

5.1 边框宽度: border-top-width, border-right-width, border-bottom-width, border-left-width 和 border-width

边框宽度属性指定了border area的宽度。取值如下:
thin
细边框
medium
中等宽度边框
thick
粗边框
<绝对数值>
边框的粗细由指定的数值确定,不能为负。
前三个值的具体大小由UA决定,但是必须满则下面这个条件:

thin <= medium <= thick

border-top-width, border-right-width, border-bottom-width, border-left-wdith四个属性分别指定了上、右、下、左四个边的边框宽度。他们可以被应用于任何元素。
border-width是上面四个属性的简写形式,如果指定了一个值,那么应用于所有的边。如果指定了两个值,那么第一个值设置top和bottom border width,第二个值设置left和right border width。如果设置了三个值,那么第一个值设置top border width,第二个值设置left和right border width,第三个值设置bottom border width。如果设置了四个值,那么依次设置top,right,bottom和left border width。

5.2 边框颜色: border-top-color, border-right-color, border-bottom-color, border-left-color 和 border-color

边框颜色属性指定了盒子边框的颜色。
边框颜色属性取值为:
<颜色>
具体的颜色值
transparent
边框透明,但是依然保持有宽度。

border-top-color, border-right-color, border-bottom-color, border-left-color指定了上、右、下、左四个边框的颜色,可以被应用于所有元素。
border-color属性是上面四个属性的简写形式,它的取值与四个属性的对应关系与border-width相同。

如果一个元素的边框颜色没有指定,那么UA可能会使用元素的color属性指定的颜色来作为边框的颜色。

5.3 边框样式: border-top-style, border-right-style, border-bottom-style, border-left-style 和 border-style

边框样式属性指定了盒子边框线条的样式(实线、双实线、虚线等)。属性的取值如下:
none
没有边框,即边框的宽度为0.
hidden
与none相同。
dotted
边框是一系列的点。
dashed
边框是虚线。
solid
边框是实线。
double
边框是双实线,两条实线加上之间的宽度等于border-width的值。
groove
边框看起来像是嵌入到画布中一样(边框凹陷效果)。
ridge
与groove的效果相反,边框看起来像是凸起来了(边框凸起效果)。
inset
边框使得盒子像是嵌入到画布中一样(盒子凹陷效果)。
outset
与inset的效果相仿,边框使得盒子像是凸起来了(盒子凸起效果)。
所有的边框都绘制在盒子的背景之上,边框的颜色取决于元素的边框颜色属性。

border-top-style, border-right-style, border-bottom-style, border-left-style、右、下、左四个边框的样式,可以被应用于所有元素。
border-style属性是上面四个属性的简写形式,它的取值与四个属性的对应关系与border-width相同。

因为边框样式的初始值为none,所有如果没有设置边框样式的话,盒子的边框不可见。

5.4 简写的边框属性: border-top, border-right, border-bottom, border-left 和 border

border-top, border-right, border-bottom和border-left属性是盒子上、右、下、左边框宽度、样式和颜色的简写形式。如:

h1 { border-bottom: thick solid red }

被省略的属性将使用它们的初始值。

H1 { border-bottom: thick solid }

border属性可以同时设置盒子的四个边框的宽度、颜色和样式。不像margin和padding属性,border属性不能给四个边框设置不同的值。

考虑如下样式,

blockquote {
  border: solid red;
  border-left: double;
  color: black;
}

左边框的颜色为黑色,其他边框的颜色为红色。因为border-left覆盖了border属性对左边框的设置,但是border-left没有设置边框颜色,所有使用了color属性指定的颜色。

6. 双向上下文中的行内元素的盒模型

对于每个行盒子,UA必须按照视觉顺序(非逻辑顺序)为这些行内盒子设置margin、border和padding。
当元素的direction属性值为ltr是,元素的第一个行盒子的最左边的行内盒子拥有left margin,left border和left padding,最后一个行盒子的最右边的行内盒子拥有right padding, right border和right margin。
当元素的direction属性值为rtl是,元素的第一个行盒子的最右边的行内盒子拥有right margin,right border和right padding,最后一个行盒子的最左边的行内盒子拥有left padding, left border和left margin。