CSS盒模型

盒模型( Box model )

在一个文档中,每个元素都被表示为一个矩形的盒子。确定尺寸, 属性等像它的颜色,背景,边框方面等和这些盒子的位置是渲染引擎的目标。在CSS中,使用标准盒模型描述这些矩形盒子中的每一个。这个模型描述了元素所占空间的内容。每个盒子有四个边:外边距边, 边框边, 内填充边 与 内容边。

css
css
  • 内容区域 (content area) 是包含元素真实内容的区域。它的大小为内容宽度 或 content-box宽及内容高度或content-box高。
    box-sizing取默认值content-box时;由 width, min-width, max-width, height, min-height 与 max-height 控制内容大小。
  • 内边距区域 (padding area) 延伸到包围padding的边框。它位于内边距边界内部, 它的大小为 padding-box 宽与 padding-box 高。
    内边距与内容边界之间的空间可以由 padding-top, padding-right, padding-bottom, padding-left 和简写属性 padding 控制。
  • 边框区域 (border area)是包含边框的区域,扩展了内边距区域。它位于边框边界内部,大小为 border-box 宽和 border-box 高。
    由 border-width 及简写属性 border控制。
  • 外边距区域 (margin area)用空白区域扩展边框区域,以分开相邻的元素。它的大小为 margin-box 的高宽。
    外边距区域大小由 margin-top, margin-right, margin-bottom, margin-left 及简写属性 margin 控制。

注意:对于非替换的行内元素来说,尽管内容周围存在内边距与边框,但其占用空间(行高)由 line-height 属性决定。
补充:低版本IE采用IE盒子模型,width = content-width,height = content-height。
参考:详解CSS盒模型

外边距合并( Margin Collapsing )

两个或多个毗邻(父子元素或兄弟元素)的普通流中的块元素垂直方向上的 margin 会发生叠加。这种方式形成的外边距即可称为外边距叠加(collapsed margin)。

有以下三种情况可能会发生外边距合并:相邻的同胞元素,父子元素,空元素。

如何避免外边距合并:

  • 父子元素的外边距合并问题可以让父元素产生BFC(比如设置overflow:hidden)或者设置padding和border。
  • 相邻兄弟元素的外边距合并问题可以设置float 或 inline-block 或 absolute。

包含块(Containing Block)

一个元素的盒模型的定位、尺寸常常会依据某个矩形(box)来计算,这个矩形就叫做这个元素的包含块(Containing Block)。

css
css

参考:CSS包含块CONTAINING BLOCK详解

层叠上下文(The stacking context)

层叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

css

层叠上下文创建条件

  • html元素
  • z-index的值不为auto的相对/绝对定位元素
  • position: fixed的元素
  • 应用了某些CSS3的元素
    • z-index的值不为auto的flex项(即父元素display: flex |inline-flex)
    • opacity小于1的元素
    • transform值不为none元素
    • min-blend-mode值不为none的元素
    • filter值不为none的元素
    • perspective值不为none的元素
    • isloation值为isolate的元素
    • will-change指定了任意属性
    • -webkit-overflow-scrolling值为touch的元素

层叠上下文特性

  • 层叠上下文的层叠水平比普通元素高;
  • 层叠上下文可以嵌套,内部层叠上下文及其所有子元素都受限- 于外部的层叠上下文;
  • 层叠上下文和兄弟元素独立,只需要考虑后代元素;
  • 每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会 在父层叠上下文中 按顺序进行层叠。

层叠上下文比较

  • 在同一个层叠上下文中,则根据7阶层叠水平比较。
  • 在不同的层叠上下文中,则直接比较父元素的层叠水平。
  • 若父元素的z-index不同,则z-index数值越大,越在上面。
  • 若父元素的z-index相同,则在DOM流中处于后面的元素会覆盖前面的元素。

注意:比较时,先看两个元素是不是在同一个父元素之下,若不是,则一层层往上找,直到找到其祖先元素在同一级时停止。然后,再依次往下寻找各自的子元素,找到第一个是层叠上下文元素的子元素后进行比较。
子元素的 z-index 值只在父级层叠上下文中有意义。即父元素的 z-index 低于父元素另一个同级元素,子元素 z-index再高也没用。

参考:层叠上下文

块格式化上下文(Block Formatting Context)

BFC(Block formatting context)直译为”块级格式化上下文”。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

BFC创建条件

  • 根元素或其它包含它的元素
  • 浮动 (元素的 float 不是 none)
  • 绝对定位的元素 (元素具有 position 为 absolute 或 fixed)
  • 内联块 inline-blocks (元素具有 display: inline-block)
  • 表格单元格 (元素具有 display: - table-cell,HTML表格单元格默认属性)
  • 表格标题 (元素具有 display: table-caption, HTML表格标题默认属性)
  • 块元素 元素具有overflow 值不是 visible
  • display: flow-root

BFC规则

  • 内部的 Box 以垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
  • 每个元素的 margin box 的左边, 与容器块的 border box 的左边相接触(对于从左往右的文字格式 (西方语言) ,否则相反)。即使存在浮动也是如此。
  • BFC的区域不会与 float box 重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算

补充:低版本IE可以通过触发hasLayout,表现出同BFC类似的效果,仅作了解。

行内格式化上下文(Inline Formatting Contexts)

行内级格式化上下文(Inline Formatting Contexts)用来规定行内级盒子的格式化规则。IFC 只有在一个块级元素中仅包含内联级别元素时才会生成。

IFC规则

  • 内部的盒子会在水平方向,一个接一个地放置。

  • 这些盒子垂直方向的起点从包含块盒子的顶部开始。

  • 摆放这些盒子的时候,它们在水平方向上的 padding、border、margin 所占用的空间都会被考虑在内。

  • 在垂直方向上,这些框可能会以不同形式来对齐(vertical-align):它们可能会使用底部或顶部对齐,也可能通过其内部的文本基线(baseline)对齐。

  • 能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和存在的浮动来决定。

  • IFC中的 line box 一般左右边都贴紧其包含块,但是会因为float元素的存在发生变化。float 元素会位于IFC与与 line box 之间,使得 line box 宽度缩短。

  • IFC 中的 line box 高度由 CSS 行高计算规则来确定,同个 IFC 下的多个 line box 高度可能会不同(比如一行包含了较高的图片,而另一行只有文本)

  • 当 inline-level boxes 的总宽度少于包含它们的 line box 时,其水平渲染规则由 text-align 属性来确定,如果取值为 justify,那么浏览器会对 inline-boxes(注意不是inline-table 和 inline-block boxes)中的文字和空格做出拉伸。

  • 当一个 inline box 超过 line box 的宽度时,它会被分割成多个boxes,这些 boxes 被分布在多个 line box 里。如果一个 inline box 不能被分割(比如只包含单个字符,或 word-breaking 机制被禁用,或该行内框受 white-space 属性值为 nowrap 或 pre 的影响),那么这个 inline box 将溢出这个 line box。

视觉格式化模型(visual formatting model)

CSS 视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制。

视觉格式化模型根据 CSS 盒模型为文档的每个元素生成 0,1 或多个盒。每个盒的布局由如下内容组成:

  1. 盒尺寸:明确指定,受限或没有指定
  2. 盒类型:行内(inline), 行内级别(inline-level), 原子行内级别(atomic inline-level), 块(block)盒;
  3. 定位方案(positioning scheme): 常规流,浮动或绝对定位;
  4. 树中的其它元素: 它的子代与同代;
  5. 视口(viewport) 尺寸与位置;
  6. 内含图片的固定尺寸;
  7. 其它信息。

一个盒相对于它的包含块(containing block) 的边界来渲染。通常盒为它的后代元素建立包含块。注意盒并不受它的包含块的限制,当它的布局跑到包含块的外面时称为溢出(overflow)。

Block

块级盒(block-level Box):当元素的 CSS 属性 display 为 block, list-item 或 table 时,它是块级元素 block-level 。块级元素(比如<p>)视觉上呈现为块,竖直排列。
每个块级元素至少生成一个块级盒(block-level Box)参与 BFC ,称为主要块级盒(principal block-level box)。

块容器盒(block container box):只包含其它块级盒,或生成一个行内格式化上下文(inline formatting context),只包含行内盒的叫做块容器盒子。也就是说,块容器盒要么只包含行内级盒,要么只包含块级盒。

块盒(BLock Boxes):同时是块容器盒的块级盒称为块盒(block boxes)

匿名块盒(Anonymous block boxes):有时需要添加补充性盒,这些盒称为匿名盒(anonymous boxes), 它们没有名字,不能被 CSS 选择符选中。

Inline

行内级盒(inline-level boxes):当元素的 CSS 属性 display 的计算值为 inline, inline-block 或 inline-table 时,称它为行内级元素。视觉上它将内容与其它行内级元素排列为多行。典型的如段落内容,有文本或图片,都是行内级元素。
行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文 IFC。

行内盒(Inline boxes):同时参与生成行内格式化上下文的行内级盒称为行内盒(Inline boxes)。所有display:inline 的非替换元素生成的盒是行内盒。而不参与生成行内格式化上下文的行内级盒称为原子行内级盒(atomic inline-level boxes)。这些盒由可替换行内元素,或 display 值为 inline-block 或 inline-table 的元素生成,不能拆分成多个盒。

匿名行内盒(Anonymous inline boxes):
类似于块盒,CSS 引擎有时自动生成行内盒。这些盒也是匿名的,因为它们没有对应的选择器名字。它们继承所有可继承的属性,非继承的属性取 initial。匿名行内盒最常见的例子是块盒直接包含文本,文本将包含在匿名行内盒中。空白如果使用white-space 去掉,则不会生成匿名行内盒。

行盒(Line boxes):行盒由行内格式化上下文(inline formatting context)产生的盒,用于表示一行。在块盒里面,行盒从块盒一边排版到另一边。 当有浮动时, 行盒从左浮动的最右边排版到右浮动的最左边。

结合line-height理解inline相关的盒子。参考:


深入理解line-height
css行高

补充:
替换元素:作为其他内容占位符的一个元素称为替换元素,根据标签和属性的值来显示内容的元素。比如img元素,它只是指向一个图像文件,这个文件插入到文档流中。大多数表单元素(input,根据type属性来显示内容)也是替换元素。
非替换元素:如果元素的内容包含在文档中,则称之为非替换元素。比如一个段落的文本都在该元素本身之内,这个段落就是一个非替换元素。
区别:

  1. 对于非替换元素,比如a,span标签等
    (1)可以设置margin-left和margin-right属性,无法设置margin-top和margin-bottom属性
    (2)行内元素border和padding可以设置,但是border-top和padding-top到页面顶部后就不再增加
  2. 对于替换元素,比如input,img标签margin,padding,border都有效果