1.盒模型是CSS的基石之一,它指定元素如何显示以及(在某种程度上)如何相互交互。页面上的每个元素被看作是一个矩形框,这个框由元素的内容、内边距、边框和外边距组成。
内边距出现在内容周围。如果在元素上添加背景,那么背景会应用于由内容和内边距组成的区域。添加边框会在内边距的区域外边加一条线。在边框的外边是外边距。外边距是透明的。一般使用它控制元素之间的间隔。
在CSS中,width和height指的是内容区域的宽度和高度。增加内边距、边框、外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。假设框的每个边上有10像素的外边距和5像素的内边距,如果希望这个框达到100像素宽,就需要将内容的宽度设置为70像素。
2.外边距叠加是一个相当简单的概念。简单的说,当两个或者更多垂直外边距相遇时,它们将形成一个外边距。这个外边距的高度等于两个发生叠加的外边距的高度中的较大者。
当一个元素包含在另一个元素中时(假设没有内边距或者边框将外边距分隔开),它们的顶或底外边距也会发生叠加。尽管看上去有些奇怪,但是外边距甚至可以与自身发生叠加。假设有一个空元素,它有外边距,但是没有内边距和边框。在这种情况下,顶外边距与底外边距就碰到了一起,它们会发生叠加。
只有普通文档流中块框的垂直外边距才会发生外边距叠加。行内框、浮动框或绝对定位框之间的外边距不会叠加。
3.CSS中有3种基本的定位机制:普通流、浮动和绝对定位。顾名思义,普通流中元素框的位置由元素在HTML中的位置决定。
块级框从上到下一个接一个地垂直排列,框之间的垂直距离由框的垂直编剧计算出来。
行内框在一行中水平排列。可以使用水平内边距、边框和外边距调整它们的水平间距。但是垂直内边距、边框、外边距不影响行内框的高度。同样在行内框设置显式的高度和宽度也没有影响。但是设置行高可以增加这个框的高度。
4.CSS的position属性设置元素的定位方式,为将要定位的元素定义定位规则。该属性在将动画特效脚本化时尤其有用。初始值为static。
定位元素是计算后位置属性为relative、absolute、fixed或sticky的元素。
相对定位元素是计算后位置属性为relative的元素 。
绝对定位元素是计算后位置属性为absolute或fixed的元素。
粘性定位元素是计算后位置属性为sticky的元素。
static
该关键字指定元素使用正常的布局行为,即元素在文档流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。
relative
该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative 未定义对 table-*-group, table-row, table-column, table-cell, table-caption 元素应用的效果。
absolute
不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。
fixed
不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的栈上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。
sticky
元素先按照普通文档流定位,然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: sticky 对 table 元素的效果与 position: relative 相同。
5.相对定位是一个非常容易掌握的概念。如果对一个元素进行相对定位,它将出现在它所在的位置上。然后可以通过设置垂直或者水平的位置,让这个元素“相对于”它的起点移动。如果将top设置为20像素,那么框将出现在原位置顶部下面20像素的地方。如果将left设置为20像素,那么会在元素左边创建20像素的空间,也就是将元素向右移动。在使用相对定位的时,无论是否移动元素仍然占据原来的空间。因此,移动元素会导致它覆盖其他框。
6.相对定位元素并未脱离文档流,而绝对定位元素则脱离了文档流。在布置文档流中其他元素时,绝对定位元素不占据空间。绝对定位元素相对于最近的非static定位的祖先元素定位。当这样的祖先元素不存在时,则相对于根级容器定位。
7.固定定位与绝对定位相似,但元素的包含块为viewport视口。该定位方式常见于创建在滚动屏幕时仍固定在相同位置的元素。
8.粘性定位是相对定位和固定定位的混合。元素在跨越阈值之前为相对定位,之后为固定定位。
9.CSS中float属性可以使一个元素脱离正常的文档流,然后被安放到它所在的容器的左端或者右端,并且其他文本和行内元素环绕着它。浮动元素指那些float属性不为none的元素。
left
表明元素必须浮动在其所在的块容器左侧的关键字。
right
表明元素必须浮动在其所在的块容器右侧的关键字。
none
表明元素不进行浮动的关键字。
inline-start
关键字,表明元素必须浮动在其所在块容器的开始一侧,在ltr脚本中是左侧,在rtl脚本中是右侧。
inline-end
关键字,表明元素必须浮动在其所在块容器的结束一侧,在ltr脚本中是右侧,在rtl脚本中是左侧。
10.清除浮动可以对想要清除浮动的元素使用clear属性,但是这个方法只是在同一块级格式化上下文中没有其他浮动元素时才是有效的。如果不能使用清除浮动,另一种做法是浮动容器的限制块级格式化上下文。
11.块级格式化上下文
CSS > 译文:理解CSS中的块级格式化上下文
块级格式化上下文(Block Formatting Context)是网页CSS视觉渲染的一部分,并用于决定块盒子的布局。在定位体系(Positioning Scheme)中它属于常规流(Normal Flow)。根据W3C所言:
浮动、绝对定位元素(position为 absolute或 fixed)、行内块元素 display:inline-block、表格单元格display:table-cell、表格题 display:table-caption 以及 overflow 属性值不为 visible 的元素(除了该值被传播到视点 viewport 的情况)将创建一个新的块级格式化上下文。
上面的引言差不多总结了一个BFC是如何形成的。但让咱们用另外一种更通俗易懂的方式来重定义它。一个BFC就是一个HTML盒子,它至少满足以下条件之一:
float 的值不为 none
position 的值不为 static 或 relative
display 的值为 table-cell、table-caption、inline-block、flex 或 inline-flex
overflow 的值不为 visiable
创建一个块级格式化上下文
一个BFC可以显式触发。如果我们想创建之,我们只需给它添加上面提到的任何一个CSS样式。
比如,看下面的HTML:
<div class="container">
Some Content here
</div>
一个新的BFC可以通过给容器添加任意一个必要的CSS样式来创建,比如overflow: scroll,overflow: hidden,display: flex,float: left,或 display: table 。尽管上述条件都可以创建BFC,但也会产生一些其他效果,如:
display: table 可能引发响应性问题
overflow: scroll 可能产生多余的滚动条
float: left 将把元素移至左侧,并被其他元素环绕
overflow: hidden 将裁切溢出元素
所以无论何时,当要创建一个BFC时,我们要基于需求选择最恰当的样式。为了保持一致性,我在本文的所有例子中均使用overflow: hidden。
.container { overflow: hidden;}
你可以自由选择使用除 overflow: hidden 之外的其他样式。
BFC中盒子的对齐
W3C规范道:
在BFC上下文中,每个盒子的左外侧紧贴包含块的左侧(从右到左的格式里,则为盒子右外侧紧贴包含块右侧),甚至有浮动也是如此(尽管盒子里的行盒子 Line Box 可能由于浮动而变窄),除非盒子创建了一个新的BFC(在这种情况下盒子本身可能由于浮动而变窄)。
简单来说,如上图所示,所以属于BFC的盒子都左对齐(在从左到右的格式下)并且它们的左外侧紧贴包含块的左侧。在最后一个盒子中我们可以看到尽管左侧存在一个浮动元素(棕色),另外一个元素(绿色)仍然紧贴包含块的左侧。该情况的产生原理将在下文关于文字环绕的部分中讨论。
BFC造成的外边距折叠
在常规流中,盒子从包含块的顶部开始一个个地垂直摆放。两个同胞盒子间的垂直举例由两个盒子各自的外边距所决定,但不是二者外边距之和。
为便于理解,我们看个例子。
在上图中,一个红盒子(div)包含着两个同胞绿元素(p),一个BFC已经创建了出来。
<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
</div>
相应的CSS是:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}
理论上两个同胞元素间的外边距应当是二者外边距之和(20px)但实际上却是10px。这就是众所周知的外边距折叠(Collapsing Margins)。如果同胞元素外边距不同,将应用最大的那个。
使用BFC避免外边距折叠
在讨论了上面BFC折叠外边距的情况后,现在说避免折叠可能有点让人摸不着头脑。但我们必须牢记于心的一件事是,相邻块级盒子(同胞)之间的垂直外边距只有在它们处于同一个BFC时才会发生折叠。如果它们分属于不同的BFC,就不会折叠了。所以,通过创建新的BFC我们可以避免外边距折叠。
让我们在早前的例子中添加第三个同胞元素,现在HTML是:
<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
<p>Sibling 3</p>
</div>
CSS是:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}
结果和上面一样,即是说,折叠还是会发生并且三个同胞间分隔的垂直距离是10px。这是因为三个 p
标签都从属于同一个BFC。
现在我们修改第三个同胞元素,使之成为一个新的BFC的一部分。现在的HTML变成了:
<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
<div class="newBFC">
<p>Sibling 3</p>
</div>
</div>
CSS:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
margin: 10px 0;
background-color: lightgreen;
}
.newBFC {
overflow: hidden; /* creates new block formatting context */
}
现在输出的结果就有所不同了:
因为第二个和第三个同胞元素现在分属于不同的BFC,它们之间就不会发生外边距折叠了。
使用BFC包含浮动
BFC可以包含浮动。我们经常遇到容器中含有浮动元素的情况。这种情况下容器元素没有高度并且其浮动子元素脱离了网页的常规流。我们通常用清除浮动解决这个问题,最普遍的做法就是使用伪元素。但我们也可以通过创建一个BFC来解决问题。
看个例子:
<div class="container">
<div>Sibling</div>
<div>Sibling</div>
</div>
CSS:
.container {
background-color: green;
}
.container div {
float: left;
background-color: lightgreen;
margin: 10px;
}
在上面这个例子中,容器没有任何高度,并且它包不住浮动子元素。为解决此问题,我们通过添加 overflow: hidden
来在容器中创建一个新的BFC。修改后的CSS成了:
.container {
overflow: hidden; /* creates block formatting context */
background-color: green;
}
.container div {
float: left;
background-color: lightgreen;
margin: 10px;
}
现在容器可以包住浮动子元素,并且其高度会扩展至包住其子元素,在这个新的BFC中浮动元素又回归到页面的常规流之中了。
使用BFC避免文字环绕
有时候浮动DIV旁边的文本会环绕它(如下图1所示)而这种情况有时候并不如我们所愿,我们想要下图2的效果。要解决这个问题,我们可以用外边距,但也可以用BFC。
首先让我们弄明白为何文字会环绕。要理解这个我们必须明白,当存在元素浮动的时候,盒模型如何工作。这就是我早先讨论BFC中对齐时候的遗留问题。我们通过下图来看图1到底发生了什么。
假设HTML是:
<div class="container">
<div class="floated">
Floated div
</div>
<p> Quae hic ut ab perferendis sit quod architecto, dolor debitis
quam rem provident aspernatur tempora expedita.
</p>
</div>
上图整个黑色区域表示 p元素,如我们所见,p元素没有移位但它叠在了浮动元素之下,而p元素的行盒子(即文本行)却移位了,行盒子水平变窄来给浮动元素腾出了空间。
随着文本的增加,最后文本将环绕在浮动元素之下,因为那时候行盒子不再需要移位,也就成了图1的样子。这就是为什么即便有浮动元素,段落仍紧贴包含块的左侧,而行盒子会变窄来给浮动元素腾位子。
如果我们能位移整个 p元素,这个环绕问题也就迎刃而解了。
在说解决方案之前,我们再回顾下W3C规范:
在BFC上下文中,每个盒子的左外侧紧贴包含块的左侧(从右到左
格式里,则为盒子右外侧紧贴包含块右侧),甚至有浮动也是如此
(尽管盒子里的行盒子 Line Box可能由于浮动而变窄),除非盒
子创建了一个新的BFC(在这种情况下盒子本身可能由于浮动而变窄)。
据此,如果 p 元素创建一个新的BFC那它就不会再紧贴包含块的左侧了。给 p 元素添加 overflow: hidden 就能轻而易举地办到。这解决了文本环绕浮动对象的问题。
在多列布局中使用BFC
如果我们创建一个占满整个容器宽度的多列布局,在某些浏览器中最后一列有时候会掉到下一行。这可能是因为浏览器四舍五入了列宽从而所有列的总宽度会超出容器。但如果我们在多列布局中的最后一列里创建一个新的BFC,它将总是占据其他列先占位完毕后剩下的空间。
我们来举个三列布局的例子:
这是HTML:
<div class="container">
<div class="column">column 1</div>
<div class="column">column 2</div>
<div class="column">column 3</div>
</div>
CSS:
.column {
width: 31.33%;
background-color: green;
float: left; margin: 0 1%;
}/* Establishing a new block formatting context in the last column */
.column:last-child {
float: none;
overflow: hidden;
}
现在尽管盒子的宽度稍有改变,但布局不会打破。当然,对多列布局来说这不一定是个好办法,但能避免最后一列下掉。这个问题上弹性盒或许是个更好的解决方案,但这个办法可以用来说明元素在这些环境下的行为。