写这篇文章的原由是源于这篇文章:谈谈面试与面试题 中关于position的讨论,文中一开始就说的这句话:css
面试的时候问个css的position属性能刷掉一半的人这是啥状况……html
其实这问题我原本打算的是能够顺着一路扯到normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,这样一路问下去的,奈何第一个问题(亲我真的只问了position有哪些取值和行为啊)就悲剧了……git
说到position,那么稍微对css有所了解的必然能立刻说出它的四个属性值:static 、relative、absolute、fixed。可是更深一步去讨论,牵扯出诸如上文提到的normal flow、containing block、bfc、margin collapse,base line,writing mode,bidi,又有多少人能很好的回答完整呢,因此我想在此作一个本身的总结概括。github
1.normal flow 面试
normal flow(正常流):正常流是默认的定位方式。任何没有具体指定{position:absolute}或者{position:fixed}属性以及没有被浮动的元素都将默认得到此属性。浏览器
在这种方式里,块级元素在它们的包含块里一个一个垂直延伸,行内元素在它们的包含块里从左至右的水平排布。app
值得注意的是,在正常流里垂直边距(vertical margin)是重叠的。也就是说,上下两个块级盒之间的边距由它们之中边距较大的元素决定,而不是他们的和!ide
1 <style>
2 div 3 {
4 width: 100px;
5 height: 100px;
6 border: 1px solid #00A4CC;
7 background-color: #3e8f3e;
8 }
9 .div1 10 {
11 margin:20px 0;
12 }
13 .div2 14 {
15 margin:40px 0;
16 }
17 </style>
18 </head>
19
20 <body>
21 <div class="div1"></div>
22 <div class="div2"></div>
23 </body>
效果显示以下:布局
div1和div2的垂直距离由大的margin决定,也就是div2的40px而不是两者之和60px。性能
其次,行内元素是会被折断的,当宽度受到限制的时候,它会自动移动到下一行。这可能会产生一些难看的效果若是行内块有边框的话。看下面的效果:
1 <head>
2 <style>
3 div 4 {
5 width: 200px;
6 height: 100px;
7 border: 1px solid #00A4CC;
8 }
9
10 span 11 {
12 border: 2px solid #00ff00;
13 }
14 </style>
15 </head>
16
17 <body>
18 <div>
19 <span> 我会掉到下一行我会掉到下一行我会掉到下一行</span>
20 </div>
21 </body>
效果显示以下:
2.containing block
containing block(包含块):是视觉格式化模型的一个重要概念,它与框模型相似,也能够理解为一个矩形,而这个矩形的做用是为它里面包含的元素提供一个参考,元素的尺寸和位置每每是由该元素所在的包含块决定的。也就是说一个元素盒子的位置和大小有时是经过相对于一个特定的长方形来计算的,这个长方形就被称之为元素的 containing block。
一个元素的containing block按照如下方式定义:
用户代理(好比浏览器)选择根元素做为 containing block(称之为初始 containing block)。
对于其它元素,除非元素使用的是绝对位置,containing block 由最近的块级祖先元素盒子的内容边界组成。
若是元素有属性 'position:fixed',containing block 由视口创建。
若是元素有属性 'position:absolute',containing block 由最近的 position 不是 static 的祖先创建,按下面的步骤:
若是祖先是块级元素,containing block 由祖先的 padding edge 造成。
若是祖先是内联元素,containing block 取决于祖先的 direction 属性。
若是 direction 是 ltr(左到右),祖先产生的第一个盒子的上、左内容边界是 containing block 的上方和左方,祖先的最后一个盒子的下、右内容边界是 containing block 的下方和右方。
若是 direction 是 rtl(右到左),祖先产生的第一个盒子的上、右内容边界是 containing block 的上方和右方,祖先的最后一个盒子的下、左内容边界是 containing block 的下方和左方。
5.若是没有祖先,根元素盒子的内容边界肯定为 containing block。
名词解释:
视口:经过解析文档,连续媒体(好比屏幕就是连续媒体,而打印机则是基于页的媒体)给用户产生一个视口(一个窗口或其它在屏幕上显示的区域)。
根元素:源文件中,每个元素都有一个父元素,只有一个例外,它就是根元素。
padding edge:请参见下图:
举个板栗:
1 <html>
2 <head>
3 <title>Illustration of containing blocks</title>
4 </head>
5 <body id="body">
6 <div id="div1">
7 <p id="p1">This is text in the first paragraph...</P>
8 <p id="p2">This is text 9 <em id="em1"> in the 10 <strong id="strong1">second 11 </strong> paragraph. 12 </em>
13 </p>
14 </div>
15 </body>
16 </html>
那么,在没有指定任何position的状况下,上方代码的containng block肯定方式为:
若是咱们设置div1的position为:
1 #div1 { position: absolute;}
此时,div1 的 containing block 就再也不是 body,它变成了初始 containing block(由于这里尚未具备 position 的祖先盒子)。
3.BFC
BFC(Block Formatting Context 块格式化上下文):是W3C CSS 2.1 规范中的一个概念,在CSS3中被修改成flow root。格式化则代表了在这个环境中,元素处于此环境中应当被初始化,即元素在此环境中应当如何布局等。元素若是建立了BF么BFC决定了如何对其内容进行定位,以及它与其余元素的关系和相互做用。
通俗理解:首先BFC是一个名词,是一个独立的布局环境,咱们能够理解为一个箱子(其实是看不见摸不着的),箱子里面物品的摆放是不受外界的影响的。转换为BFC的理解则是:BFC中的元素的布局是不受外界的影响(咱们每每利用这个特性来消除浮动元素对其非浮动的兄弟元素和其子元素带来的影响。)而且在一个BFC中,块盒与行盒(行盒由一行中全部的内联元素所组成)都会垂直的沿着其父元素的边框排列。
建立了BFC的元素会按照以下的方式对其子元素进行排列:
名词解释:
边距折叠:在CSS当中,相邻的两个盒子(多是兄弟关系也多是祖先关系)的外边距能够结合成一个单独的外边距。这种合并外边距的方式被称为折叠,而且于是所结合成的外边距称为折叠外边距。
折叠的结果:
产生折叠的必备条件:margin必须是邻接的,且须要知足以下条件:
那么,什么状况下会建立BFC:
值得注意的是,"display:table" 自己并不产生 "block formatting contexts"。可是,它能够产生匿名框, 其中包含 "display:table-cell" 的框会产生块格式化上下文。
总之,对于 "display:table" 的元素,产生块格式化上下文的是匿名框而不是 "display:table"。
最后,是这些元素建立了块格式化上下文,它们自己不是块格式化上下文。
BFC的运用:消除浮动与多栏布局。
1.自适应两栏布局
1 <style>
2 body {
3 position: relative;
4 }
5
6 .aside {
7 width: 100px;
8 height: 150px;
9 float: left;
10 background: #f66;
11 }
12
13 .main {
14 height: 200px;
15 background: #fcc;
16 }
17 </style>
18 <body>
19 <div class="aside"></div>
20 <div class="main"></div>
21 </body>
效果以下:
根据BFC的规则:
每个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来讲,则触碰到右边缘)
因此,虽然存在浮动的元素aslide,但main的左边依然会与包含块的左边相接触。
所以,咱们能够根据:
BFC的区域不会与float box重叠。
来经过触发main生成BFC,实现自适应两栏布局。
1 .main { 2 overflow: hidden; 3 }
当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。所以会根据包含块的宽度,和aside的宽度,自动变窄。效果以下:
2.清除内部浮动
1 <head>
2 <title>Clear float</title>
3 <style>
4 .container{
5 margin: 30px auto;
6 width:600px;
7 height: 300px;
8 }
9 .wrapper{
10 border:solid 3px #a33;
11 }
12 .main{
13 width: 100px;
14 height: 100px;
15 background-color: #060;
16 margin: 10px;
17 float: left;
18 }
19 </style>
20 </head>
21 <body>
22 <div class="container">
23 <div class="wrapper">
24 <div class="main"></div>
25 <div class="main"></div>
26 <div class="main"></div>
27 </div>
28 </div>
29 </body>
但愿的结果是:
但结果是:
父容器并无把浮动的子元素包围起来,俗称塌陷,为了消除这种现象,除了用传统的伪类方法。根据
计算BFC的高度时,浮动元素也参与计算
还可使父容器造成BFC,来清除浮动,简单修改一下代码:
<div class="wrapper" style="float:left;"> //添加一个float属性,造成BFC <div class="main">1</div>
<div class="main">2</div>
<div class="main">3</div>
</div>
能够获得以下效果:
总结来讲,BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
由于BFC内部的元素和外部的元素绝对不会互相影响,所以,当BFC外部存在浮动时,它不该该影响BFC内部Box的布局,BFC会经过变窄,而不与浮动有重叠。一样的,当BFC内部有浮动时,为了避免影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理。