理解CSS盒模型

/ 前端 / 没有评论 / 810浏览

CSS 是层叠样式表(Cascading Style Sheets)的简称。在网页制作中,用于将内容和表现分离,好处是减少代码量,提高页面浏览速度。它的语法规则是 选择器{属性:值} 。 学习 CSS 进行设计和布局时,必须要了解它的盒子模型原理。

一、什么是盒子模型

在一个文档中,每个HTML元素被表示为一个矩形的盒子。确定盒子的尺寸、属性(颜色、背景、边框、位置)是渲染引擎的目标。

在CSS中,使用标准盒子模型来描述这些矩形盒子中的每一个。这个模型描述了元素所占空间的内容。每个盒子有四个边:外边距(margin)、边框(border)、内部填充(padding)、内容(content)。

下面的图片说明了盒子模型(Box Model)。 alt 最外面橙色的就是外边距区域(margin area ),往里黄色的是边框区域(border area),再往里的绿色的是内边距区域(padding area ),最里面绿色的就是内容区域(content area)了。

二、盒模型的两个核心问题

每当我们谈论css盒模型的时候,往往会涉及到盒模型延伸出来的两个问题

业界的前端工程师都不怎么青睐IE系的浏览器,甚至对它有点嫌弃。我们这里不讨论这些历史遗留原因,只讨论W3C标准盒模型和IE盒模型各自的原理。

2.1 W3C标准盒模型

假设有一个盒子的css属性如下:

box {
  width: 200px;
  height: 180px;
  border: 5px solid #666;
  margin: 10px;
  padding: 10px;
}

那么,这个盒子需要占据的尺寸为:

盒子的宽度 = 内容宽度 + 左填充 + 右填充 + 左边框 + 右边框 + 左边距 + 右边距
盒子的高度 = 内容高度 + 上填充 + 下填充 + 上边框 + 下边框 + 上边距 + 下边距

盒子的宽度 = width + padding-left + padding-right + border-left + border-right + margin-left + margin-right
         = 10 + 5 + 10 + 200 + 10 + 5 + 10
         = 250
盒子的高度 = height + padding-top + padding-bottom + border-top + border-bottom + margin-top + margin-bottom
         = 10 + 5 + 10 + 180 + 10 + 5 + 10
         = 230

简单的概括就是,盒子在页面占据的大小包括了margin,border,padding以及content。而盒子的实际大小(这里的实际大小,通过调试工具inspect可以看出来)包括border,padding以及内容区域content,但是不包括margin。

另一点需要说明的是,我们通过JavaScript代码获取某一个元素的大小时,所得到的width和height其实是盒子模型中的content的大小。

2.2 IE盒模型

IE盒模型也包含margin,border,padding以及content这几部分。 IE盒模型与标准盒模型的核心差异是:IE盒模型的content部分包含了border和padding。

同样的,对于上面假设的盒子,在IE盒模型下,这个盒子需要占据的尺寸为:

盒子的宽度 = margin-left + content-width + margin-right
    = 10 + 200 + 10
    = 220
盒子的高度 = margin-top + content-height + margin-bottom
    = 10 + 180 + 10
    = 200

而盒子的实际大小为:

宽度 = content.width
    = 200
高度 = content.height
    = 180

2.3 盒模型在不同情况下的表现

2.3.1 块级元素盒模型的默认宽度

如果一个块级元素未声明明确的宽度,并且是 static 或者 relative 定位,那么他的宽度将会保持100%的宽度(这里的100%指的是其最近父层元素content的宽度),同时盒子的padding和border会向内推动而不是向外扩展。

2.3.2 无宽度的绝对定位盒子

未设置宽度的绝对定位(position: absolute)的盒子的表现与之前有点不同。它的宽度只需要适合它们所包含的内容即可。因此,如果盒中只有一个单词,盒子就会像那个词的表现一样宽。如果变成两个词,盒子的宽度也会相应增加。 alt alt 这种情况会持续到盒子的宽度达到父层元素宽度的100%(最近的相对定位的父元素或者浏览器窗口),如果再超出,文本就会发生折行。

2.3.3 内联元素的盒模型

不管是块级元素还是内联元素,在页面上的展现抽象都是盒子。不能为内联元素设置宽度或高度,或者通过改变其展示方式来设置其宽高(display: inline-block)。

三、box-sizing属性

box-sizing属性是 CSS3 的 盒模型属性之一。盒子的宽度和高度的计算方式由box-sizing属性控制。

描述说明
content-box这是由 CSS2.1 规定的宽度高度行为。宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框。此值为其默认值,其让元素维持W3C的标准盒模型
border-box为元素设定的宽度和高度决定了元素的边框盒。就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。此值让元素维持IE传统的Box Model(IE6以下版本)
inherit规定应从父元素继承 box-sizing 属性的值

box-sizing属性现代浏览器都支持,但IE家族只有IE8版本以上才支持,虽然现代浏览器支持box-sizing,但有些浏览器还是需要加上自己的前缀。

假设我们有这样的一个场景,设置子类元素的margin或者border时,可能会撑破父层元素的尺寸,这时我就需要使用box-sizing: border-box来将border包含进元素的尺寸中,这样就不会存在撑破父层元素的情况了。

表单中有一些input元素其实还是展现的是传统IE盒模型,带有一些默认的样式,而且在不同平台或者浏览器下的表现不一,造成了表单展现的差异。此时我们可以通过box-sizing属性来构建一个风格统一的表单元素。

最佳实践

为了布局上的方便,一些专家建议我们将所有的元素都设置为box-sizing: border-box,具体原因可以参考这篇文章: International box-sizing Awareness Day

如果不考虑低版本浏览器的话,可以用下面的代码:

*,
*:before,
*:after { 
  box-sizing: border-box;
}

后来,又有专家建议用的继承的方法,如下:

html {
  box-sizing: border-box;
}
*,
*::before,
*::after {
  box-sizing: inherit;
}

这种方法被称为最佳实践,具体原因就不说了,参考这里:Inheriting box-sizing Probably Slightly Better Best-Practice 既然是专家推荐 ,那我们以后可以把第二种方法的段代码放到reset.css里面的。