认识浮动元素已经好久了,可是最开始只用它来对齐文档,最近整理笔记又复习到双飞翼布局和圣杯布局。这两种布局的实现,偏偏也是借助了浮动流的魔力。在笔记中搜索‘’float‘’或者‘’浮动‘’,能够找到10个条目,结合着旧知识,今天再复习一波。css
浮动元素,正如其名,它“浮”在文档表面,不占据正常文档流,咱们让一个元素浮动很简单,只要设置float属性便可,可让它浮动到父元素的最左边或者最右边。html
img {
float: left;
}
复制代码
浮动布局最开始是用来实现杂志上的图片和文字混排,主要是文字围绕图片的效果。布局
<img align = 'right'>
来实现这一功能。
后来,Web开发者们发现使用float能够浮动任何元素,不只仅是images,并且因为浮动的特性,后一个浮动元素贴着前一个浮动元素(假设它们都向左浮动),因此浮动还能够用来布局,特别是多列布局。spa
如今随着Flex布局,以及一些其余布局技巧的出现,Float用来布局只能算做是过期的技术,可是正是因为它的魔力,咱们实现了不少难以想象的布局。最为出名的,仍是圣杯布局和双飞翼布局了。3d
浮动元素不占据文档流,所以后面的元素会当它不存在,可是有如下几点须要注意:code
1. 若是其兄弟元素是块级元素,会当它不存在而覆盖它orm
2. 若是是行内元素,则是会围绕它cdn
3. 若是兄弟是块级元素可是其内容是行内元素,那么这些行内元素仍是会围绕浮动元素htm
有一个经典的三栏布局问题:左右边栏宽度固定,中间栏宽度自适应,可是中间部份内容较为重要,须要首先渲染(也就是先出如今DOM中),该如何实现?blog
若是单单提到三栏布局,不限制三栏在DOM中顺序的话,网上有不少方法,我记得比较深入的是下面两种。
See the Pen 三栏布局 - 绝对定位和自身浮动 by Tian Zhi ( @tianzhich) on CodePen.
- 左右两栏相对父元素container进行绝对定位,中间一栏设置左右margin分别等于边栏宽度。这种作法中间一栏出如今DOM中的位置都OK
- 自身浮动布局:左右两边分别向左和向右浮动,中间一栏出如今DOM最后面,因为浮动元素脱离文档流,中间栏设置好左右margin等于边栏宽度便可
固然,除了上面两种,还可使用Flex布局,以及接下来提到的圣杯布局,双飞翼布局。
圣杯布局来源于2006年发表在alistapart的一篇文章In Search of the Holy Grail。圣杯有西方“渴求之物”的意思,可能也是想说明这个布局在当时的重要性。
圣杯布局解决的是三栏布局问题:左右边栏宽度固定,中间栏宽度自适应,可是中间部份内容较为重要,须要首先渲染(也就是先出如今DOM中)。
<div id="container">
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
</div>
复制代码
圣杯布局采用的方法是让父元素container使用padding为左右两边预留出空间,而后中间占比100%,三栏天然浮动,例如:
#container {
padding: 0 200px;
}
#center {
float: left;
width: 100%;
height: 400px;
background-color: red;
}
#left {
float: left;
height: 200px;
width: 200px;
background-color: pink;
}
#right {
float: left;
height: 200px;
background-color: blue;
width: 200px;
}
复制代码
效果图以下:
此时咱们只须要让左右两边分别上去,怎么上去呢?正常流来讲是上不去的(设置负的margin-left很大只会让它从左边溢出文档)。而浮动流,却可让它们上去。这里咱们先看圣杯和双飞翼的实现结果,浮动流的秘密最后再给出详细解释。
这里咱们让左边栏margin-left: -100%
,右边栏margin-right: -200px
(自身宽度)使它们的位置发生偏移
注意
- 以前看到一些解释都是左右两边都是相对布局,其实否则,包括圣杯布局那篇文章给出的也只是左边使用了相对布局,看上面的图也能明白,右边已经到了正确的位置
- 若是右边必定要使用相对布局的话,则右边栏是设置为
margin-left: -200px
,而后相对布局,向右位移200px,这里设置margin-left
和margin-right
在表现上有细微的不一样,最后面给出了个人一些见解
最后设置左边position: relative; right: 200px
便可
再来看看双飞翼。
双飞翼布局解决的问题和圣杯布局同样,都是三栏布局,中间自适应,中间最早出如今DOM中,那为什么还要出现双飞翼布局。由于圣杯布局会出现坍塌,所以听说淘宝UED发明了双飞翼布局,从名字来看,双飞翼比圣杯更能描述这种布局。
圣杯布局在中间一栏宽度小于两边任意一栏时,会不起做用,仍是刚才的例子,只不过把中间栏宽度缩小。
为何会这样,你可能会想,明明两边空白还足够啊?这也和浮动流有关,若是着急了解,你能够直接往下看。而这里先知道圣杯布局会失败,所以才有更好的双飞翼布局出现。
双飞翼布局相对于圣杯布局,再也不让父元素给左右两边腾出位置,而中间一栏又不知道宽度。这样其实中间一栏居中只能设置margin-left = margin-right
为左右两栏宽度,可是因为最终要把左右两栏位移上来(只能经过浮动流),可是浮动流必须设置宽度(width或padding或border),不然将不存在。与中间栏不知道宽度形成矛盾。
双飞翼布局使用了一个trick,多用了一个div,在中间栏div下再使用一个div用来显示content(这里我再也不使用container,能够认为container就是body)。
<div class="main">
<div class="main-content"></div>
</div>
<div class="left"></div>
<div class="right"></div>
复制代码
这样作能够设定中间一栏的宽度为100%,而真正的内容区域设置好左右margin给左右边栏留出位置便可,而后让外面这层父元素进行浮动。
.main {
width: 100%;
float: left;
}
.main-content {
background-color: pink;
margin: 0 200px;
height: 300px;
}
.left {
background-color: red;
width: 200px;
height: 150px;
float: left;
}
.right {
background-color: blue;
width: 200px;
height: 150px;
float: left;
}
复制代码
注意这里和圣杯的不同,因为左右栏的直接父元素为body(没有限制宽度),所以它们靠在了最左边。
咱们让左边margin-left: -100%
,右边margin-left:-200px
:
直接一步到位并且不会坍塌。
最后给出对浮动流流动的我的看法,以及对上面两个布局给出详细解释。
咱们先看看MDN上对于浮动元素位置的基本解释。
when an element is floated, it is taken out of the normal flow of the document (though still remaining part of it). It is shifted to the left, or right, until it touches the edge of its containing box, or another floated element.
意思就是一个元素若是设置为浮动,会抽离文档流,以float: left
为例,会向左移动,直到其碰到其父元素的左边距或者是其他的浮动元素。
若是元素均向左浮动,浮动流从左向右。那么,当一行空间不足会怎么样呢?看一个例子:
See the Pen 浮动流如何流 by Tian Zhi ( @tianzhich) on CodePen.以上元素均向左浮动,第三个元素没有空间了,此时它并不是直接另起一行,而是在第二个元素下方向左移动,直到遇到第一个浮动元素边界。
基于这个原则,咱们能够知道浮动元素若是换行,是基于它本来位置并向左移(假设float: left
)。
咱们先来看圣杯布局和双飞翼布局中,左右边栏未上去的状况。
<div class="main">
<div class="main-content"></div>
</div>
<div class="left"></div>
<div class="right"></div>
复制代码
双飞翼中父元素(body)宽度为100%。左边栏紧靠中间栏div.main-content
外层容器div.main
的右边,见上图。
因为设置负的margin-left
值,可让元素回流,100%则是相对于父元素的width
而言的,所以双飞翼布局就很好解释了。
再来回过头看圣杯布局:
<div id="container">
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
</div>
复制代码
对于圣杯布局,父元素div#container
宽度即为div#center
宽度。左边栏的位移和双飞翼同样,只不过上去以后再使用相对定位往左偏移。而对于右边栏,位移上去使用的是负的margin-right
,负的margin-right
的做用是使文档流后面的元素回流,并且可能覆盖它自身,因此在这里换一种方式或许好理解一些。
以前提到父元素宽度不够,因此左边栏会换到下一行,设置负的
margin-right
,能够用它抵消掉自身的width
,在不考虑border
的状况下,若是所有抵消(盒子宽度为0),就仿佛本身不存在。第一行天然能够容纳它,结果就会流回去。可是要记住,使用负的margin-left
是使自身发生偏移,而负的margin-right
抵消自身宽度,只是伪装本身不存在,并不会发生位移,也就是说,哪怕margin-right
绝对值再大,它也只能牢牢挨着前一个浮动元素边界。
所以咱们直接让右边栏伪装本身不存在从而移到上一行。
再来看看刚才那张图:
看完前面的解释,这里也不难理解为何左右两边上不去了:
margin-left: -100%
,并不能彻底抵消掉自身宽度,所以上不去margin-right
为负的自身宽度,即便抵消掉自身宽度,可是因为它的浮动位置位于左边栏以后,不能跨过左边栏进行位移,因为左边栏上不去,所以,右边栏也没法上去而双飞翼则彻底没有这个问题,由于父元素的width不受限,左右边栏彻底只须要使用负的margin-left
发生位移,移动到本身的位置上去便可。