The CSS box model describes the rectangular boxes that are generated for elements in the document tree and laid out according to the visual formatting model. CSS盒模型描述了通过 文档树中的元素 以及相应的 视觉格式化模型(visual formatting model)所生成的矩形盒子。
当浏览器对一个 render tree 进行渲染时,浏览器的渲染引擎就会根据 基础盒模型(CSS basic box model) ,将所有元素划分为一个个矩形的盒子,这些盒子的外观,属性由 CSS
来决定。
我们在浏览器控制台输入如下代码就可以看到页面的每一个元素都是由一个矩形来包裹的,这些就是盒子。
$$('*').forEach(e => {
e.style.border = '1px solid';
})
图示如下:
CSS 的视觉格式化模型(visual formatting model) 是根据 基础盒模型(CSS basic box model) 将 文档(doucment) 中的元素转换一个个盒子的实际算法。 官方说法就是: 它规定了用户端在媒介中如何处理文档树( document tree )。
每个盒子的布局由以下因素决定:
视觉格式化模型(visual formatting model) 的计算,都取决于一个矩形的边界,这个矩形,被称作是 包含块( containing block ) 。一般来说,(元素)生成的框会扮演它子孙元素包含块的角色;我们称之为:一个(元素的)框为它的子孙节点建造了包含块。包含块是一个相对的概念。
例子如下:
<div>
<table>
<tr>
<td>hi</td>
</tr>
</table>
</div>
以上代码为例, div
和 table
都是包含块。div
是 table
的包含块,同时 table
又是 td
的包含块,不是绝对的。
图示:(图片来自w3help):
盒子的生成是 CSS视觉格式化模型 的一部分,用于从文档元素生成盒子。盒子的类型取决于
CSS display
属性。 格式化上下文(formatting context) 是定义 盒子环境 的规则,不同 格式化上下文(formatting context) 下的盒子有不同的表现。
以下是盒子相关的概念定义:
块级元素
display
为 block
、 list-item
或 table
时,它就是块级元素。块级盒子
匿名盒子1.某些情况下需要进行视觉格式化时,需要添加一些增补性的盒子,这些盒子不能被 CSS选择器
选中,也就是所有可继承的 CSS 属性值都为 inherit
,而所有不可继承的 CSS 属性值都为 initial
。因此称为匿名盒子(anonymous boxes)。
行内元素
display
为 inline
、 inline-block
或 inline-table
时,它就是行内级元素。行内盒子
行内格式化上下文(inlineformatting context)
的创建。匿名行内盒子
initial
。display:run-in
来设置,它既可以是块盒子,又可以是行内盒子,这取决于它后面的盒子的类型。BFC 这个概念来自于 视觉格式化模型(visual formatting model) 中的 正常流(Normal flow)。
浮动、绝对定位元素、块容器(例如inline-blocks、table-cells、and table-captions)以及溢出而非可视的元素(除非该值已经传播到了视口)都是建立 BFC(Block formatting contexts) 的条件。
在BFC(Block formatting contexts)中,在包含块内一个盒子一个盒子不重叠地垂直排列,两个兄弟盒子直接的垂直距离由 margin
决定。浮动也是如此(虽然有可能两个盒子的距离会因为 floats
而变小),除非该盒子再创建一个新的BFC。
鱼头注:简单来说,BFC就是一个独立不干扰外界也不受外界干扰的盒子啊(/ω\)。
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width'+ 'margin-right' = 包含块的宽度
上面的计算法则是基于 writing-mode:ltr
而言,如果是别的书写顺序,则按照该顺序来计算。
如果宽度不是 auto 或者 'border-left-width'+'padding-left'+'width'+'padding-right'+'border-right-width' 的结果大于包含块的宽度,对于以下规则,被视为零。
如果只有一个值指定为'auto',则其使用的值来自相等。
如果宽度设置为 auto ,则任何其他 auto 值变为 0 ,并且宽度会跟着所以盒子的情况铺满。
如果 'margin-left' 跟 'margin-right' 都为 auto ,则会使元素相对于包含块的边缘水平居中。
如果 'margin-left' 跟 'margin-right' 都为 auto ,则它们的具体值为 0 。
如果宽度为 auto,则使用 shrink-to-fit 的宽度计算方式(CSS 2.2没有定义精确的算法)。
然后 shrink-to-fit 大概的计算方式则是:min(max(preferred minimum width, available width), preferred width)。
'left' + 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + 'right' = 包含块的宽度
如果 'left','width' 和 'right' 都是 'auto',则首先将 'margin-left' 和 'margin-right' 的 'auto' 值设置为 0。
如果 'left','width' 和 'right' 都不是 'auto',则按照实际值来算。
如果 'margin-left' 跟 'margin-right' 都为 0 ,则根据 'left' ,'width' 和 'right' 的值是否是 'auto' 来计算。如果 一个方向值 ,'width' 的值是 'auto',而 '另一个一个方向值' 不是,则宽度使用 shrink-to-fit 算法计算。如果一个值为'auto'而另外两个值不算,则该值使用 shrink-to-fit 来计算。
上面的计算法则是基于 writing-mode:ltr
而言,如果是别的书写顺序,则按照该顺序来计算。
鱼头注:这里特别说明一点,在MDN中依然把flexbox跟gridbox 算在 BFC中,但在最新的规范里,它们已经从BFC中分离了出去,成为独立的一个CSS模块,内容如下: