基础-盒子模型
基本概念: 标准宽度计算模型 + IE宽度计算模型
什么是盒模型: 盒子模型又称框模型(Box Model), 包含了元素内容(content), 内边距(padding), 边框(border), 外边距(margin)几个要素.
标准模型和IE模型的唯一区别在于内容计算方式的不同:
- IE模型元素宽度 width = content + padding + border
- 标准模型元素宽度 width = content
CSS 设置盒子模型
CSS3新增了box-sizing: content-box | border-box分别设置盒模型宽度的计算方式, content-box宽度为content的width值, border-box的width为content + padding + border的宽度值.
JS获取和设置盒子模型宽高
dom.style.width/height: 可以获取到行内样式的宽和高,style标签中和link外链的样式是获取不到的.dom.currentStyle.width/height: 获取到的是最终渲染后的宽和高, 只有IE支持此属性window.getComputedStyle(dom).width/height: 同上一条, IE9以上支持dom.getBoundingClientRect().width/height: 获取渲染后的宽高, 大部分浏览器支持, IE9以上支持, 除此外还能获取到相对于视窗的上下左右的距离.
盒子模型
CSS中存在几种不同的盒子, 有两种基础的模型(这里的模型不是我们上面说到的宽度计算标准模型):
- 块级盒子(
block-level box): 负责结构 - 内联盒子(
inline box): 负责内容
也有一些比较特殊的模型, 比如用于li样式的:
- 标记盒子(
marker box): 用来表示圆点, 数字等项目符号.
一个元素总会又两种盒子构成: 盒子和容器盒子.
以display的不同属性, 我们就能知道它是由哪两种不同的盒子组成的:
display: block: block盒子+block容器盒子display: inline-block: inline盒子+block容器盒子display: inline-table: inline盒子+table容器盒子
block盒子和table盒子都是块级盒子的一种
width
width 隐含了四种宽度计算方式:
fill-available(充分利用可利用空间), 例如div,p这些元素fit-content(收缩与包裹), 例如浮动, 绝对定位, inline-block元素和table元素min-content(收缩到最小), 比如在table-layout为auto时的情况max-content(超出容器限制), 无视父容器的宽度限制而超出的情况
内部尺寸和外部尺寸
- 内部尺寸(Intrinsic Sizing), 表示尺寸由内部元素决定
- 外部尺寸(Extrinsic Sizing), 表示尺寸由外部元素决定
外部尺寸与流体特性
- 正常流宽度: 容器会自然的铺满整个宽度
- 格式化宽度: 在绝对定位模型中, 宽度会由内部尺寸决定. 但当
left/right或者top/bottom同时存在的时候, 元素的宽度就会表现为格式化宽度. 其宽度大小相对于最近的具有定位特性的祖先元素计算. 格式化宽度具有完全的刘提醒, 也就是margin,border,padding,content内容区域同样会自动分配水平(垂直)区域.
内部尺寸与流体特性
- 包裹性. 包裹性除了包裹还有自适应性, 指的是元素尺寸有内部元素决定, 但永远小于包含块容器的尺寸(除非容器尺寸小于元素的"首选最小宽度").
- 首选最小宽度: 指元素最合适的最小宽度. 对于不同的文字, 规则有些不同:
- 对于东亚文字, 最小宽度为每个汉字的宽度
- 对于西方文字, 最小宽度由特定的连续英文字符单元决定
- 对于图片这样的替换元素的最小宽度, 就是该元素内容本身的宽度
- 最大宽度: 元素可以有的最大宽度
height: auto
一般来说, height: 100%是不会生效的, 想要实现这样的效果, 有两种方法:
- 设定显式的高度值. 比如设置父元素为
600px - 使用绝对定位. 如此一来即便祖先元素的
height为auto, 也能使高度进行计算. 不过区别于非绝对定位元素的百分比计算, 绝对定位的宽高百分比计算是相对于padding-box的, 而非绝对定位元素则是相对于content-box进行计算的
min/max-height/width
min-height/width初始值为 auto- 超越
!important:max-width会覆盖width, 即便width设置了!importtant - 超越最大:
min-width会覆盖max-width, 当这两者冲突的时候.
内联元素
内联元素的内联特指"外在盒子", 这和display为inline不是同一个概念.
内联盒模型
内联盒包含了很多种的盒子, 可以归结为:
- 内容区域(content area). 内容区域指一种围绕文字的看不见的盒子, 其大小仅受字符本身特性控制, 本质上是一个字符盒子.
- 内联盒子(inline box). 内联盒自会让内容排成一行.
- 行框盒子(line box). 每一行就是一个"行框盒子", 每个行框盒子由一个个的内联盒子组成
- 包含盒子(containing box). 在CSS规范中, 更准确的称呼是"包含块"(containing block). 由一个一个的行框盒子组成.
BFC
BFC 既 Block Formatting Contexts (块级格式化上下文), 属于普通流的一种.
常见的定位方案
定位方案指的是控制元素布局的方式, 常见有三种方案:
- 普通流(normal flow)
在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。
- 浮动(float)
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。
- 绝对定位 (absolute positioning)
在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。
BFC 概念
具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。
通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。
如何触发 BFC
只要元素满足下面任一条件即可触发 BFC 特性:
- body 根元素
- 浮动元素:float 除 none 以外的值
- 绝对定位元素:position (absolute、fixed)
- display 为 inline-block、table-cells、flex
- overflow 除了 visible 以外的值 (hidden、auto、scroll)
BFC 特性
- 同一个 BFC 中外边距会发生折叠
<head>
<style>
div {
width: 100px;
height: 100px;
background: lightblue;
margin: 100px;
}
</style>
</head>
<body>
<div></div>
<div></div>
</body>
两个 div 的元素的间距只会是 100px, 而不是 200px;
想要避免这种情况可以创建两个不同的 bfc 盒子:
<style>
.container {
overflow: hidden;
}
p {
width: 100px;
height: 100px;
background: lightblue;
margin: 100px;
}
</style>
<div class="container">
<p></p>
</div>
<div class="container">
<p></p>
</div>
- BFC 可以包含浮动的元素(清除浮动)
浮动的元素会脱离普通文档流.
<div style="border: 1px solid #000;">
<div style="width: 100px;height: 100px;background: #eee;float: left;" />
</div>
只要触发容器的 BFC, 就可以清除浮动:
<div style="border: 1px solid #000;overflow: hidden">
<div style="width: 100px;height: 100px;background: #eee;float: left;" />
</div>
- BFC 可以阻止元素被浮动元素覆盖
<div style="height: 100px;width: 100px;float: left;background: lightblue">我是一个左浮动的元素</div>
<div style="width: 200px; height: 200px;background: #eee">我是一个没有设置浮动,
也没有触发 BFC 元素, width: 200px; height:200px; background: #eee;</div>

如果想要避免这种覆盖, 就可以手动触发 BFC, 即在第二个元素中加入overflow: hidden.

这个方法可以用来实现两列自适应布局. 左边宽度固定, 右边宽度自适应(去掉宽度)
其他上下文
我们这里介绍了 BFC(Block formatting contexts), 块级格式上下文. 这里实际上还有其他的上下文:
IFC
IFC(Inline formatting contexts):内联格式上下文 IFC 的 line box(线框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的 padding/margin 影响)IFC 中的 line box 一般左右都贴紧整个 IFC,但是会因为 float 元素而扰乱。float 元素会位于 IFC 与与 line box 之间,使得 line box 宽度缩短。 同个 ifc 下的多个 line box 高度会不同 IFC 中时不可能有块级元素的,当插入块级元素时(如 p 中插入 div)会产生两个匿名块与 div 分隔开,即产生两个 IFC,每个 IFC 对外表现为块级元素,与 div 垂直排列。 那么 IFC 一般有什么用呢? 水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生 IFC,通过 text-align 则可以使其水平居中。 垂直居中:创建一个 IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。
GFC
GFC(GrideLayout formatting contexts):网格布局格式化上下文 当为一个元素设置 display 值为 grid 的时候,此元素将会获得一个独立的渲染区域,我们可以通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间。那么 GFC 有什么用呢,和 table 又有什么区别呢?首先同样是一个二维的表格,但 GridLayout 会有更加丰富的属性来控制行列,控制对齐以及更为精细的渲染语义和控制。
FFC
FFC(Flex formatting contexts):自适应格式上下文 display 值为 flex 或者 inline-flex 的元素将会生成自适应容器(flex container),可惜这个牛逼的属性只有谷歌和火狐支持,不过在移动端也足够了,至少 safari 和 chrome 还是 OK 的,毕竟这俩在移动端才是王道。Flex Box 由伸缩容器和伸缩项目组成。通过设置元素的 display 属性为 flex 或 inline-flex 可以得到一个伸缩容器。设置为 flex 的容器被渲染为一个块级元素,而设置为 inline-flex 的容器则渲染为一个行内元素。伸缩容器中的每一个子元素都是一个伸缩项目。伸缩项目可以是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说,Flexbox 定义了伸缩容器内伸缩项目该如何布局。