CSS魔法堂:说说Float那个被埋没的志向

简介:

前言

 定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了;2. 它跟Normal flow靠得太近了。本文尝试理清Float的特性和行为特征,若有纰漏望各位指正。

被埋没的志向——文字环绕

 回忆一下我们一般什么时候会想用浮动呢?是多列布局还是多列布局呢:)?其实它向往的却是这个
347002-20160410220152078-2065773468.jpg
它想干的就是这个——文字环绕,而且CSS2中除了浮动外没有其他属性可实现上述的效果。
那到底如何理解它的实现原理呢?下面我们采取分步剖析的方式来深入探讨吧!

切断关联看Float

'float'
Value: left | right | none | inherit
Initial: none
Applies to: all
Inherited: no
当设置float:left后,元素对应的margin left edge会尽可能向所属的containing block的左边框靠近,若同一行中存在位于左侧的元素设置了float:left,则即会尽可能向该兄弟元素的margin right edge靠近.

<div style="background:#06F;width:200px;height:100px;position:relative;left:20px;">
  <div style="background:#1F0;width:50px;height:50px;float:right;"></div>
  <div style="background:#F60;width:50px;height:50px;float:right;"></div>
</div>

347002-20160410220219734-315457632.jpg
(由于float:left突出不了效果,因此采用float:right作例子。其中蓝色区域就是containing block范围,绿和红色块采用向右浮动)
当设置浮动后,display:inline的实际值将被改写为display:block,因此不要再为display:inline;height:100px;line-height:0;float:left导致盒子content height为100px感到惊讶了。也不要为即使剩余空间不足以存放整个display:inline;float:left盒子,导致整个盒子下移到下一行排版而惊讶了.(若为Normal flow则会根据white-spacing、word-wrap和word-break决定盒子内部分内容换行,而不是整个盒子换行)简单来说并不是float:left让盒子具有不为五斗米折腰的气质,而是display:block的功劳,又由于浮动的盒子会以水平方向排版,因此我们可以以display:inline-block来理解浮动定位的水平排版和换行行为。

<div style="background:#06F;width:200px;height:100px;">
  <span style="background:yellow;width:100px;height:50px;float:left;">I'm span</span>
  <span style="background:#F01;width:110px;height:50px;float:left;">I'm span too</span>
</div>

347002-20160410220233047-1773963384.jpg
当设置浮动后,虽然display的实际值为block但就width:auto而言,我认为display更像是采用inline-block,宽度由子元素决定。这就是包裹性了!
(float:right同理,只是方向不同而已)
注意:在仅考虑浮动元素本身的前提下,float:left的效果与display:inline-block而父容器direction:ltr的效果是一样的,不同的是浮动元素不纳入父容器高度的计算当中

<div style="border:solid 1px #06F;">
  <span style="background:#F01;float:left;">float:left</span>
</div>
<br clear="both"/><br/>
<div style="border:solid 1px #06F;">
  <span style="background:#F01;display:inline-block;">float:none</span>
</div>

347002-20160410220244890-1640942454.jpg

头痛的开始——基于Normal flow看Float

 用割裂的方式理解float并不难,难就难在结合Normal flow看Float。下面我们一起来探讨吧!警告,前方高能,前方高能!!

以Normal flow为基础

 不管是Absolute positioning还是Float均以Normal flow作为定位基础,也就是说先假设有一个虚拟盒子以Normal flow进行定位,然后在这个基础上添加Float的特性并影响其他盒子的布局。而浮动定位对于盒子自身而言仅影响其在水平方向上的定位,因此对于inline-level box而言其垂直方向上的定位并没有发生变化,而对于block-level box而言因Collapsing margins的失效有可能会引起垂直方向上的移动。
347002-20160410220257547-155466623.jpg

<div style="background:#0f6;width:200px;height:50px;margin-bottom:50px;"></div>
<div style="background:#f06;width:200px;height:50px;margin:50px 0;"></div>
<div style="background:#06F;width:200px;height:50px;margin-top:50px;float:left;">float:left</div>

值得注意的是,浮动定位的虚拟盒子实际上是不占空间的。因此才有后续的浮动闭合和清除浮动的事。

压榨line box

347002-20160410220348093-1577607208.jpg
文字环绕很明显就是活生生地把文字向两边挤,为"大哥"留下个位置,而且小弟们不要走太远,必须时刻拥护着大哥。那大哥是如何圈住小弟们的呢?那得借助外力——line box。文字是以字形(glyph)的形式渲染,和它同一行的inline-level boxes均位于同一个line box中。而line box可谓是夹在containing block和浮动盒子之间勉强生存。
347002-20160410220358703-133764098.jpg

<div style="overflow:hidden;line-height:1.5;background:#06F;">
<img src="john.png" style="float:left;margin:10px"/>
These days it takes a diverse and complex collection of components to power a web browser. <img src="john.png" style="float:right;margin:10px"/>It’s fair to think of all those parts coming together as a single piece of machinery, and we often talk about our web platform as an “engine”.
</div>

 若line box的宽度不足以容纳glyph和inline-level boxes时,会在下方产生N个新的line boxes并在必要时拆分inline-level boxes,然后将glyph和inline-level boxes分布到各行的line boxes当中。

脚踩block-level box

 相对line box,block-level box就显得不屈不挠了。width:auto时其宽度始终保持占满containing block宽度的态度。但位于同一个stacking context中的浮动定位的盒子虽然和常规流中的盒子拥有相同的z-index(都是auto),但浮动定位的盒子拥有额外的优先级,导致它总位于常规流中的盒子之上。(关于分层显示的内容可参考《CSS魔法堂:你真的理解z-index吗?》
347002-20160410220413250-1691488750.jpg

<div style="float:left;border:solid 1px red;width:100px;height:50px;">float:left</div>
<div style="background:#06f;width:200px;height:100px;"></div>

通过创建BFC翻身做主人

 同样是盒子,为啥你就可以在我上面呢?你有Float罩着,我也找弄个新的BFC来跟你抗衡。我们知道通过float:left|rightposition:absolute|fixeddisplay:inline-block|table-cell|table|table-captionoverflow:auto|scroll|hidden均可让盒子产生新的BFC。而产生BFC的盒子间天生排斥彼此。(但可通过后天的努力position:relative让他们又互有交集^_^)
那现在的问题是采用Normal flow定位模式的会产生新的BFC的盒子到底是紧跟在Float定位盒子的后面,还是另起一行呢?答案是两者都有可能,具体看剩余的宽度是否足以容纳该盒子。其实就是如同设置父容器产生BFC,而该盒子采用Float定位模式。不信,你看

<div style="float:left;border:solid 1px red;width:100px;height:50px;">float:left</div>
<div style="background:#06f;width:200px;height:100px;overflow:hidden;"></div>

347002-20160410220431609-1458387114.jpg

是"浮动闭合"还是"清除浮动"?

 我想各位都看过各种版本的clearfix实现,而最简单粗暴的方式就是添加一个<div style="clear:both"></div>来清除浮动。我还听过另一个名称——"浮动闭合",那到底两者有什么区别呢?在作区分之前我们先要明确问题的本身。
对于height:auto的容器而言,我们希望它能恰好包裹着所有子元素,但不幸的是采用浮动定位模式的子元素将不纳入父容器的高度计算当中,那就会出现子元素戳穿父容器的风险。
从之前的内容我们了解到文字和inline-level boxes会环绕Float定位的盒子,而block-level box则被它踩在脚下。但现在希望后续盒子不再与Float定位的盒子有任何瓜葛。
面对这两种需求,我们分别得出"浮动闭合"和"清除浮动"两套方案。

浮动闭合

 就是让height:auto的父容器包裹所有子元素,包括Float定位的子元素。方式很简单,就是好让父容器产生BFC。

清除浮动

 就是为浮动影响的范围划边界。方式也很简单,就是以一个clear:left|right|both的盒子作为边界即可,其实就是引入空隙(clearance)。
首先clear属性仅对block-level box有效clear:left表示盒子的margin-left-edge不与浮动盒子接触,而clear:right表示盒子的margin-right-edage不与浮动盒子接触,clear:both自然是左右两条margin-edge均不与浮动盒子接触啦。有点虚,直接看疗效吧!

<div style="float:left;width:200px;height:50px;background:#06F;">float:left</div>
<div style="clear:left;width:200px;height:50px;background:#F60;">clear:left</div>
<div style="float:right;width:200px;height:50px;background:#06F;">float:right</div>
<div style="clear:right;width:200px;height:50px;background:#F60;">clear:right</div>

347002-20160410220446718-743044947.jpg

 简单地说就是float:leftclear:left来清除,float:rightclear:right来清除。而我们会发现一个怪异的现象,那就是设置clear:left|right|both的盒子的border top edge紧接着Float定位盒子的margin bottom edge,其实这是clearance来作祟。当设置clear:left|right|both的盒子A的border top edge与Float定位盒子B的margin box重叠时,那么就会在A的margin box和border top edge之间引入clearance,恰好让A的的border top edge恰好不与B的margin bottom edge重叠。

<div style="margin-bottom:50px;background:#06F;height:100px;width:200px;float:left;"></div>
<div style="margin-top:50px;border: solid 10px red;height:50px;width:200px;clear:left;"></div>

347002-20160410220513312-503306664.jpg

.clearfix方案

 不管是浮动闭合也好,清除浮动也罢,我们的目的往往是两者结合——Float定位的范围与Normal flow定位的范围分明,且采用Normal flow的父容器包裹所有子元素。那么可归结为Normal flow的父容器包裹所有子元素。因此得到如下的HTML Markup

<div class="container clearfix">
   <!-- Float定位的范围 -->
</div>
<!-- Normal flow定位的范围 -->

而具体的方案如下:
方案1

.clearfix::after{
  content: ".";
  display: block;
  clear: both;
  line-height: 0;
  visibility: hidden;
}
.clearfix{
  *zoom: 1; /*for IE5.5/6/7*/
}

伪元素after表示创建一个display:block,innerText是content属性值的元素作为该元素的最后一个子元素。注意content属性值不能为空白,否则无法清除浮动。
方案2

.clearfix::after{
  content: "\u200B"; /*通过零宽空白字符,省略visibility属性*/
  display: block;
  clear: both;
  line-height: 0;
}
.clearfix{
  *zoom: 1; /*for IE5.5/6/7*/
}

注意:若页面不是采用UTF-8编码方式,那么\u200B表示的将不是零宽空白字符,从而导致方案2出问题。
方案3
由Nicolas Gallagher大湿提出的

.clearfix::before, .clearfix::after{
  content: "";
  display:table;
}
.clearfix::after{
  clear: both;
}
.clearfix{
  *zoom: 1; /*for IE5.5/6/7*/
}

这里有2个奇妙的地方:

  1. 通过display:table让即使content为空白时,也能独占据一行,且高度为0;(原理是display:table会生成一个block-level box包裹着伪元素after)
  2. 通过伪元素before消除父容器margin-top与第一个Normal flow的子元素的margin-top产生margin collapsing效果。

浮动真的是定位模式的一员吗?

 我们可以通过position属性来设置Normal flow或Absoluting positioning,但却要通过float属性来设置Float,这让我一度怀疑Float到底是不是定位模式的一员呢?
我是这样理解的,Normal flow(包括Relative positioning)与Absoluting positioning是非我即你的关系,而Float和Relative positioning则是可叠加影响定位效果的关系,显然必须另设一个属性来设置更恰当。

期待更美的文字环绕

 有没有发现通过float:left|right我们仅能得到要么图片靠左要么图片靠右的文字环绕效果,那如果我们希望得到如下的四周环绕的效果呢?
347002-20160410220709797-1935906450.jpg
虽然已有案例是通过absolute positioning模拟出类似的效果,但布局排版固定导致无法适应大部分场景。如果有个float:both属性值那该多好啊!另外大家是否觉得以下的环绕效果更有艺术范呢?
347002-20160410220721297-1188507079.jpg
听说通过CSS3的shapes特性可以实现四周环绕和上面非四四方方的环绕效果,日后好好研究研究!
2016/04/19补充-参考《CSS网站布局实录-基于Web标准的网站设计指南(第2版)》的5.2.2 不规则文字环绕
347002-20160419230534382-1271919387.jpg

<style type="text/css">
.article{
  font-size: 14px;
  line-height: 1.5;
  text-align: justify;
}
.figure{
  position: absolute;
  z-index: -1;
}
.figure-shape{
  margin: 0;
  padding: 0;
}
.figure-shape li{
  list-style-type:none;
  height: 1.5em;

  float: left;
  clear: left;
}
.figure-shape li:nth-child(1){
  width: 150px;
}
.figure-shape li:nth-child(2){
  width: 180px;
}
.figure-shape li:nth-child(3){
  width: 180px;
}
.figure-shape li:nth-child(4){
  width: 160px;
}
.figure-shape li:nth-child(5){
  width: 148px;
}
.figure-shape li:nth-child(6){
  width: 150px;
}
.figure-shape li:nth-child(7){
  width: 148px;
}
.figure-shape li:nth-child(8){
  width: 144px;
}
.figure-shape li:nth-child(9){
  width: 136px;
}
</style>
<div class="article">
<img src="./beyonce.jpg" class="figure"/>
<ul class="figure-shape"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul>
初中时候语文老师说我会是个写作天才,因为我写的东西足够真实,取材身边,造句简单,用语文书垫桌脚的同时翻烂了韩寒的1988,那时督促我已经成为她的习惯。时至今日再次遇见语文老师时候我惭愧的告诉她我已经不写文了,也没有像她说的那样成为一个天才,我只能微微一笑告诉她我至少还没停下笔。
</div>

总结

重构了几次总算写完了,想写得清楚而又不哆嗦真心不易,继续努力:)
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/5375753.html^_^肥子John

感谢

KB011: 浮动(Floats)
KB009: CSS 定位体系概述
CS001: 清理浮动的几种方法以及对应规范说明
CSS float浮动的深入研究、详解及拓展(一)
CSS float浮动的深入研究、详解及拓展(二)
https://www.w3.org/TR/CSS2/visuren.html#flow-control
CS001: 清理浮动的几种方法以及对应规范说明
Faking ‘float: center’ with Pseudo Elements
说说标准——CSS核心可视化格式模型(visual formatting model)之十:控制紧接浮动的排列-clear 特性
那些年我们一起清除过的浮动

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!

posted @ 2016-04-11 08:59 ^_^肥仔John 阅读( 867) 评论( 1) 编辑 收藏
  
#1楼 3405706 2016/4/12 10:12:12 2016-04-12 10:12 站在枫中  
好文!

公告

 
 
本文转自 ^_^肥仔John博客园博客,原文链接: http://www.cnblogs.com/fsjohnhuang/p/5375753.html,如需转载请自行联系原作者
相关文章
|
3月前
|
前端开发
CSS float(浮动)
CSS float(浮动)
30 2
|
5月前
|
前端开发
CSS布局讲解-float浮动布局使用
CSS布局讲解-float浮动布局使用
|
11月前
|
前端开发 容器
前端祖传三件套CSS的布局之float
作为前端开发的必备技能,CSS布局一直是我们需要不断掌握和学习的重要内容。在CSS中,float布局是最经典、最常用的一种布局方式。本文将介绍float布局的基本概念、使用方法、注意事项,并结合实例进行讲解。
158 0
|
11月前
|
前端开发
css的学习(下)两千字入门css的几种布局(flex,grid,float...)
# 规则生效问题 ## 优先级 特异度的值来决定的 ### 选择器的特异度 Sqecificity id (伪)类 标签 #id .class tag 百 十 个 # 继承 某些属性会自动继承其父元素的计算值 除非显示的 指定一个值 文字相关的,颜色,字体 不给会继承 一些盒子模型 大小 不会继承 ## css可以和不可以继承的属性 不可继承的:display、margin、border、padding、background、height、min
|
前端开发
web前端-CSS(display,position,overflow和浮动float)
web前端-CSS(display,position,overflow和浮动float)
110 0
|
前端开发 容器
CSS之我是一个浮动元素(float)
大家好,我是一个浮动元素,我在CSS王国中是一个很重要的角色,也许你们现在在工作中很少见到我的身影,因为我的flex兄弟和position定位兄弟在大部分情况下可以取代我,但是我还是想详细的介绍一下我自己,毕竟我曾经也是一个在前端开发中随处可见的明星人物。
117 0
CSS之我是一个浮动元素(float)
|
前端开发
web前端-CSS(display,position,overflow和浮动float)
display(显示) display属性指定由元素生成的框的类型,通常用到display对应值有block、none、inline这三个值。 下面我们来看看display的属性有哪些吧。
web前端-CSS(display,position,overflow和浮动float)
|
前端开发
web前端学习(二十四)——CSS3浮动属性(float)、清除浮动属性(clear)的相关设置
web前端学习(二十四)——CSS3浮动属性(float)、清除浮动属性(clear)的相关设置
web前端学习(二十四)——CSS3浮动属性(float)、清除浮动属性(clear)的相关设置
|
前端开发 容器
CSS - float & overflow: hidden
CSS - float & overflow: hidden
143 0
|
前端开发
CSS - Float
CSS - Float
85 0
CSS - Float