Skip to content

盒模型

在理解 CSS 是如何控制页面显示效果的时候,我们必须要掌握盒模型(Box Model)和定位(position)机制。CSS 借助于盒模型和定位机制,结合文档树,能够精确、高效地控制内容在页面中的位置,从而实现页面的布局。

盒模型的概念

所有 HTML 元素,在页面的呈现过程中,都遵循 CSS 制定的盒模型(Box Model),盒模型是一个包含外边距、边框线、内边距以及内容的矩形容器。具体如下图所示:

从图中我们可以看到,元素的盒模型由外边距 (margin)、边框线 (border)、内边距(padding)以及元素的内容(content)构成,CSS 对外边距、边框线、内边距的控制可以分方向进行,也可以整体控制,如上图中的 TM 就表示上侧外边距、LM 表示左侧外边距、RM 表示右侧外边距、BM 表示底侧外边距。

在 CSS 中,直接用来描述盒模型的属性有 margin、border、padding、width、height。需要注意的是,CSS 提供的宽度属性(width)和高度属性(height)指的是内容区域(content)的宽度和高度,而不是整个盒模型的宽度和高度。整个盒模型的大小应该包括内外边距及边框的宽度。

盒模型的宽度 = “margin-left” + “border-left” + “padding-left” + “width” + “padding-right” + “border-right” + “margin-right

盒模型的高度 = “margin-top” + “border-top” + “padding-top” + “height” + “padding-bottem” + “border-bottom” + “margin-right

设置盒子大小

在 CSS 中,可以使用盒模型的 widthheight 属性为除行内元素之外的大多数元素设置高度和宽度。行内元素的宽度和高度取决于自身内容。

宽度和高度的值可以为百分比、带单位的长度或者是 auto。如:

#content {
width: 90%;
height: 300px;
}

百分比的计算是按照父元素的大小来计算,而不是按照本身的大小。如果没有指定宽度,盒模型就是用默认值 100%,也就是说和所在容器的宽度一样,如果没有指定高度,浏览器则会根据内容自动计算出高度大小。

除了 widthheight 之外,CSS 还提供了 max-heightmax-widthmin-heightmin-width 属性。

设置外边距

外边距用来控制元素之间的距离,在 CSS 中,使用 margin 属性来控制外边距,外边距是透明的空间量。内容之间适当的空间能够增加内容的可读性。除行内元素不接受上下外边距的设定外,其他元素都可以设定外边距。

margin 属性的值可以是带单位的长度、百分比和 auto。设置外边距的方式如下:

div {
margin: 10px;
}

上述规则表示 div 元素四侧的外边距为 10 个像素。

div {
margin: 10px 20px;
}

上述规则表示 div 元素上下侧的外边距为 10 个像素,左右侧的外边距为 20 像素。

div {
margin: 10px 20px 5px;
}

上述规则表示 div 元素上侧的外边距为 10 像素,左右两侧的外边距为 20 像素,下侧的外边距为 5 像素。

div {
margin: 10px 20px 0 5px;
}

上述规则表示 div 元素上侧的外边距为 10 像素,右侧的外边距为 20 像素,下侧外边距为 0,左侧外边距为 5 像素。

除了使用 margin 统一设定元素外边距外,CSS 还提供了 margin-topmargin-rightmargin-bottom 以及 margin-left 四个属性分别设定各侧的外边距。

需要特别说明的是,当元素左右两侧的外边距取值 auto 时,这个元素就会在所在容器中居中。如:

div {
margin: 0 auto;
}

设定内边距

CSS 中使用 padding 表示内边距,内边距和外边距在很多方面是相似的。padding 的值可以是带单位的长度或者是百分比。padding 属性值中没有 autopadding 属性值可以是 1-4 个值,其意义与 margin 相同。padding 也可以分侧指定,如 padding-toppadding-rightpadding-bottompadding-left

设置边框

边框是进行信息组织是的一种有效手段,通过边框的使用,能够区分不同类型的信息,而且边框还是一种装饰手段,能在组织信息的同时美化页面。CSS 提供了 border-styleborder-widthborder-color 以及 border 元素来控制边框的样式、宽度以及颜色。如:

#footer {
border-style: dashed;
border-width: 1px;
border-color: #ccc;
}

上述规则将使得 idfooter 的元素四周拥有灰色、1 个像素宽度的虚线边框。

其中 border-style 的属性值用来指定边框线的样式,默认值为 none,也就是没有边框,因此,在定义边框属性时,border-style 实际上是必须要指定的,常用的值有:solid, double, dashed, dotted, and none

border-width 的属性用来指定边框先的宽度,宽度值为带单位的长度(如 1px)或关键字(thinmediumthick),宽度默认值为 medium

border-color 属性用来指定边框颜色,其值可以为文本、16 进制颜色值和 rgb 函数值,颜色的默认继承元素内容的颜色。

CSS 还提供了快速设定边框样式的属性——border,如上述的样式可以这样简写:

#footer {
border: dashed 1px #ccc;
}

border 的值中必须要指定的是 border-style,其他两个可以任意组合,并且对出现的先后顺序也无要求。和 marginpadding 属性类似,border-styleborder-width 以及 border-color 可以接受 1-4 个值,用以分别指定不同侧面的边框样式,如下面的样式规则使得 idfooter 的元素上下两侧没有边框,左右两侧的边框样式为虚线、宽度为 medium、颜色和该元素的内容颜色一致:

#footer {
border-style: none dashed;
}

最后,CSS 也提供了分别指定不同方向上边框的机制:border-topborder-rightborder-bottom 以及 border-left。如下面的样式规则将使得 idfooter 的元素拥有 1 个像素宽的红色虚线上边框:

#footer {
border-top: dashed 1px red;
}

圆角

border-radius 属性,允许我们为元素设置圆角效果。

border-radius 属性接受长度单位,包括百分比和像素。border-radius 如果只有一个值,则设定四个角,俩值、三个值和四个值的情况与 marginpadding 类似,都按顺时针方向设定。例如:

.border-football {
border-radius: 15px 75px;
}

上述代码设定左上、右下角为半径 15 像素的圆角,而右上和左下的圆角半径为 75 像素。

外边距叠加

边距叠加(Margin Collapse)是CSS中一个重要但常被误解的概念。当两个或多个垂直方向上相邻的块级元素的外边距相遇时,它们会形成一个外边距,这个外边距的高度等于这些相遇外边距的最大值,而不是它们的总和。这种现象被称为外边距叠加。

外边距叠加的基本规则

W3C对于外边距叠加的定义如下:

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

在CSS中,两个或多个毗邻的普通流中的盒子(可能是父子元素,也可能是兄弟元素)在垂直方向上的外边距会发生叠加,这种形成的外边距称之为外边距叠加。

我们可以注意定义中的几个关键字:毗邻两个或多个垂直方向普通流

  • 毗邻说明了它们的位置关系,没有被padding、border、clear和line box分隔开。
  • 两个或多个盒子是指元素之间的相互影响,单个元素不会存在外边距叠加的情况。
  • 只有垂直方向的外边距会发生外边距叠加。水平方向的外边距不存在叠加的情况。
  • 普通流指的是不是浮动、绝对定位或根元素的元素。

外边距叠加的三种情况

外边距叠加主要发生在以下三种情况:

  1. 相邻兄弟元素之间的外边距叠加:当一个元素出现在另一个元素之后时,第一个元素的下外边距与第二个元素的上外边距会发生叠加。

    <div style="margin-bottom: 20px;">第一个div</div>
    <div style="margin-top: 30px;">第二个div</div>

    在这个例子中,两个div之间的外边距是30px,而不是50px。

  2. 父元素与第一个/最后一个子元素之间的外边距叠加 :如果父元素没有上边框和上内边距,那么父元素的上外边距会与第一个子元素的上外边距发生叠加。同样,如果父元素没有下边框和下内边距,且高度为auto,那么父元素的下外边距会与最后一个子元素的下外边距发生叠加。

    <div style="margin-top: 20px;">
    <div style="margin-top: 30px;">子元素</div>
    </div>

    在这个例子中,父div的上外边距与子div的上外边距会叠加,最终的外边距是30px。

  3. 空元素的上下外边距叠加 :如果一个元素没有内容、上下内边距或边框,那么它的上下外边距会叠加。

    <div style="margin-top: 20px; margin-bottom: 30px; height: 0;"></div>

    在这个例子中,两个div之间的外边距是30px,而不是50px。

外边距叠加的计算规则

当外边距叠加发生时,最终的外边距大小遵循以下规则:

  1. 如果参与叠加的外边距都是正值,则取其中的最大值。
  2. 如果参与叠加的外边距有正有负,则取最大的正外边距与最小的负外边距(绝对值最大的负外边距)的和。
  3. 如果参与叠加的外边距都是负值,则取绝对值最大的负外边距的值。

如何避免外边距叠加

在某些情况下,我们可能希望避免外边距叠加。以下是一些常用的方法:

  1. 使用内边距代替外边距 :在可能的情况下,使用内边距(padding)代替外边距(margin)可以避免叠加问题。

  2. 创建块格式化上下文(BFC) :以下方法可以创建BFC,从而防止外边距叠加:

    • 设置 overflow 为 auto 、 hidden 、 scroll 或 overlay
    • 设置 display 为 flow-root 、 inline-block 、 flex 或 grid
    • 设置 position 为 absolute 或 fixed
    • 设置 float 为 left 或 right
  3. 添加边框或内边距 :在父元素与子元素之间添加边框或内边距可以防止它们的外边距叠加。

  4. 使用Flexbox或Grid布局 :在Flexbox和Grid容器中,子元素不会发生外边距叠加。

参考资料

  1. https://www.w3.org/TR/CSS2/box.html
  2. https://www.w3.org/Style/css2-updates/css2/box.html#collapsing-margins