CSS定位与布局:普通流

CSS 定位与布局属于CSS的基础,也是CSS布局影响很大的一部分,具体主要包括三种定位与布局机制Positioning schemes ):普通流,浮动,绝对定位。
其实除了这三种之外,还有一些定位机制,但是这三种可以说在网站的应用是最多的,随便打开一个网站搜索一下这些属性,少则出现几十次,多则上百,官方文档也有对这三个属性的辨析< Comparison of normal flow, floats, and absolute positioning>,这篇博文很多内容是受  葵中剑@剑空 前辈的博文 CSS定位机制之一:普通流 的启发,在此感谢前辈的博文分享。
 
CSS定位与布局:普通流
 
官方文档介绍:
 
In CSS 2.1, a box may be laid out according to three positioning schemes:
1.  Normal flow. In CSS 2.1, normal flow includes  block formatting of block-level boxes,  inline formatting of inline-level boxes, and  relative positioning of block-level and inline-level boxes.
2.  Floats. In the float model, a box is first laid out according to the normal flow, then taken out of the flow and shifted to the left or right as far as possible. Content may flow along the side of a float.
3.  Absolute positioning. In the absolute positioning model, a box is removed from the normal flow entirely (it has no impact on later siblings) and assigned a position with respect to a containing block.
 
普通流( normal flow )
标准里的定义:Normal flow. In CSS 2.1, normal flow includes block formatting of block boxes, inline formatting of inline boxes, relative positioning of block or inline boxes, and positioning of run-in boxes.(这个属于CSS3新定义的属性,还未去了解)

即普通流包括:块格式化( block formatting ),行内格式化( inline formatting ),相对定位(relative positioning ),以及 run-in boxes(CSS3)的定位。

任何被渲染的元素都属于一个 box ,并且不是 block ,就是 inline 。在普通流中的 Box(框) 属于一种 formatting context(格式化上下文) ,类型可以是 block ,或者是 inline ,但不能同时属于这两者。并且, Block boxes(块框) 在 block formatting context(块格式化上下文) 里格式化, Inline boxes(块内框) 则在 inline formatting context(行内格式化上下文) 里格式化。即使是未被任何元素包裹的文本,根据不同的情况,也会属于匿名的 block boxes 或者 inline boxes。

普通流过程:
1、block formatting context:块级元素按照在HTML中的顺序,在容器框中从左到右,从上到下依次分配空间,每个块级元素独占一行,margin属性决定相邻inline-block元素距离,同一个BFC中的垂直边界被重叠(collapse)。其中,浮动的块级元素会有inline-block元素的一些表现,具体将在float定位中细讲。
 
2、inline formatting context:行内元素在容器框中的顶端开始水平排布,这里有必要说明下margin,padding,border的不同表现。
 
------------------------------------------------------举个栗子---------------------------------------------------
HTML:
1 <div class="container">

2      <a class="inlineEle" href="#">inline element</a>

3      <a class="inlineEle" href="#">inline element</a>

4 </div>
CSS:
.container{

    border: 1px solid #000;

}

.inlineEle {

    background-color: #bbb;

    border: 10px solid #000;

    margin: 10px;

    padding:20px;

    height: 100px;

    width: 300px;

}
chrome,firefox,opera,IE8+表现如下:
CSS定位与布局:普通流
 
IE6,IE7下的表现:
 
IE6,IE7下,当容器框加了height:100px后内联元素高度变为line-height,其他部分被截掉了:
CSS定位与布局:普通流
margin:水平的margin有效,但是垂直的margin不影响高度,或者说无效。
border:border的有兼容性问题,chrome,firefox,opera,IE8+下会表现出所有边框,但是垂直方向的border虽然出现了但是,并不能撑开容器框,当容器框设置overflow:hidden的时候会被hidden掉。在IE6,IE7下垂直方向的border已经不见了。其实IE5我也出于好奇测试了一下,发现居然表现和chrome等一样,实在是匪夷所思。不过IE5已经不在我的考虑之内了。
padding:padding均能表现,但是同样垂直方向的padding也无法撑开容器框,当容器框设置overflow:hidden的时候也会被hidden掉。
width,height:对于行内元素无效。
-----------------------------------------------------吃完栗子-----------------------------------------------------
 
一个水平行中的所有inline box组成了名为line box的区域,line box的高度始终容得下所有的inline box,并只有行内元素的行高能够撑开容器框。line-box的宽度受到父容器和浮动元素影响(浮动元素实现文字环绕效果)。如果line box的宽度小于容器,line box的水平排布就取决于text-align,当line box的宽度大于容器,则截断line box并换行在新的line box中重新排布元素(截断处不应用padding和margin值)。如果line box无法截断,如单词过长或者指定不换行,则会溢出容器。
 
3、对block box和inline box进行相对定位(position:relative),即相对于已排布的位置进行偏移,元素基于普通流的排布空间依然保留。
 
普通流中有一个比较重要的概念,即Formatting context。Formatting context是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。
 
最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。 
CSS2.1 中只有BFC和IFC, CSS3中还增加了GFC和FFC。下面只讲 BFC,IFC有机会再补充。
 
Block fomatting context 的创建:
  1. 根元素
  2. float属性不为none
  3. position为absolute或fixed
  4. display为inline-block, table-cell, table-caption, flex, inline-flex
  5. overflow不为visible
注:
1、 CSS level 3 specification中,BFC(CSS3中用 "flow root" 表示)在以下情况中可以建立:position 的值不为 “static” 或者 “relative” ,即 fixed 也能建立BFC,但其实fixed算是 absolute positioning 的一个子集,在规范中引用一个绝对定位的元素(或他的box模型)意味着该元素的 “position” 属性值 “absolute” 或 “fixed”,因此在CSS2.1 中使用这个值也会触发 BFC ,只是在 CSS3 中更加明确了这一点。
2、display:table 本身并没有建立BFC,但是它能够产生匿名框,匿名框(display:table-cell)才会建立BFC。
即使两种样式都建立了BFC(隐式或显式),clear 属性作用在 display:table 和 display:table-cell 是不一样的。
3、fieldset元素也能触发BFC。www.w3.org上并没有对它的表现的描述,直到HTML5的规范中才有。有一些浏览器bugs(Webkit,Mozilla)提到过,但是都不是官方声明的。参考文章的作者 Thierry Koblentz认为:即使fieldsets在大多数浏览器中都能建立BFC,也是不推荐的,CSS2.1中没有定义该属性应用于表单控件和框架,或者如何用CSS添加样式,用户代理可能可以为其提供CSS样式属性。故应该把这种支持作为实验性质的,未来版本的CSS可能会明确支持。
 
Block fomatting context 的作用与影响:
  1. 在同一个BFC中,boxes会在垂直方向,从一个containing block的顶部一个接一个放置,兄弟 boxes 的垂直距离由 ”margin“ 值决定。相邻 block boxes 的垂直 margin 会折叠(CSS2.1 8.3.1 Collapsing margins)。
  2. 在同一个BFC中,每一个 box 的左外边缘与 containing block 左边缘接触(从右到左的格式化则是右边缘接触)。即使是浮动元素(虽然一个box的line boxes会因为浮动元素而收缩),除非 box 建立一个新的BFC(会因为和浮动元素接触而收缩)。
  3. BFC 使在同一个BFC中的相邻 block boxes 的垂直margin值不会折叠。
  4. BFC能够包含浮动元素。
  5. BFC区域不会与浮动元素重叠。
  6. 计算BFC的高度时,浮动元素也参与计算。(CSS2.1 10.6.7 'Auto' heights for block formatting context roots 
  7. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
因为BFC内部的元素和外部的元素绝对不会互相影响,因此, 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会收缩而不与浮动有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理。
 
-----------------------------------------------------举几个栗子说明一下-----------------------------------------------------
栗子一(BFC 使在同一个BFC中的相邻 block boxes 的垂直margin值不会折叠):
HTML:
<div class="container">

    <div class="collapsediv">同一个BFC中的div.1</div>

    <div class="collapsediv">同一个BFC中的div.2</div>

</div>
CSS:
.container {

    border: 1px solid #000;

    overflow: hidden;

    *zoom: 1;

}

.collapsediv {

    background-color: #ccc;

    width: 300px;

    height: 100px;

    margin: 50px;

}
注:这里的*zoom:1是对IE6的hack,涉及到IE的私有属性hasLayout 。
表现如下:
CSS定位与布局:普通流
 
此时 div.1 的 margin-bottom 和 div.2 的 margin-top 重叠了,如果给下面的div.2包裹在触发了BFC的容器中,则div.1和div.2则属于不同的BFC,则margin不会折叠(此时如果在.warp元素上加padding-top或者border属性都可以使margin不重叠,效果和出发BFC相同。当然IE6、IE7除外 )。
修改后的HTML:
<div class="container">

    <div class="collapsediv_1">同一个BFC中的div.1</div>

    <div class="wrap">

        <div class="collapsediv_2">同一个BFC中的div.2</div>

    </div>

</div>
CSS:
.collapsediv{

    background-color: #ccc;

    width: 300px;

    height: 100px;

    margin: 50px;

}

.wrap {

    overflow: hidden;

    *zoom: 1;

}

.inlineEle {

    background-color: #bbb;

    border: 10px solid #000;

    margin: 10px;

    padding: 20px;

    height: 100px;

    width: 300px;

}
表现如下:
CSS定位与布局:普通流
 
栗子二(BFC能够包含浮动元素+计算BFC的高度时,浮动元素也参与计算):
HTML:
<div class="container">

    <div class="floatdiv">浮动div.1</div>

    <div class="floatdiv">浮动div.2</div>

</div>
CSS:
.container {

    border: 2px solid #000;

}

 .floatdiv {

    background-color: #ccc;

    width: 100px;

    height: 50px;

    float: left;

    border:1px solid #666;

}
表现如下:
 
浮动元素脱离了普通流,使得容器框的高度变为0,此时为容器建立BFC就可以包含浮动元素,同时也说明此时计算容器框的高度时,浮动元素也参与计算。
修改后的CSS:
container {

    border: 2px solid #000;

    overflow: hidden;

    *zoom: 1;

}
表现如下:
 
注:除了创建 BFC,还可以用清除浮动的方法,需要留意的是用 clear 清除浮动只会清除同一个BFC中的浮动元素。
 
栗子三(BFC区域不会与浮动元素重叠)
HTML代码:
<div class="container">

    <div class="floatdiv">浮动div</div>

    <div class="nofloatdiv">不浮动div</div>

</div>
CSS:
.floatdiv {

    background-color: #ccc;

    float: left;

    height: 50px;

}

.nofloatdiv {

    background-color: #999;

    height: 100px;

}

.container {

    border: 1px solid #000;

    height: 150px;

}
 
 
在chrome,firefox,opera,IE8+表现如下:
CSS定位与布局:普通流
 

IE7表现如下:

CSS定位与布局:普通流

 
IE6表现如下,这里浮动和不浮动的div之间有3px的间距,这是IE6及以下版本独有的3px的bug:
CSS定位与布局:普通流

修改CSS如下:
.nofloatdiv {

    background-color: #999;

    height: 100px;

    overflow: hidden;

    *zoom:1;

}
除了IE6表现不变外,其他浏览器(包括IE7)表现如下:
CSS定位与布局:普通流
 
-----------------------------------------------------吃完栗子-----------------------------------------------------
 
除了IE6,IE7外,和浮动元素相邻的块元素建立BFC后,不会和浮动元素重叠。而IE6、IE7在加了height属性后其实就触发了IE的私有属性hasLayout,以及IE6还存在3px的bug,这都和IE的私有属性hasLayout有关。关于hasLayout,这是IE7及更低版本所有的一个IE私有属性,和BFC有些类似,是IE兼容性的一个罪魁祸首,关于这个属性有一篇很旧但是很详实的文章 On having layout(蓝色理想转载的中文翻译版本),原文: On having layout
 
BFC总结:
BFC 神奇背后的原理的总结个人觉得不错,很容易理解,也很容易记住。此处引用一下:
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
因为BFC内部的元素和外部的元素绝对不会互相影响,因此, 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄,而不与浮动有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理。
 
参考文档:
 
参考文章:
Thierry Koblentz  CSS 101:Block Formatting Contexts . 
 
感谢文章作者。
 
水平有限,错误欢迎指正。原创博文,转载请注明出处。

你可能感兴趣的:(css)