CSS魔法堂:说说Float那个被埋没的志向
前言
定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了;2. 它跟Normal flow靠得太近了。本文尝试理清Float的特性和行为特征,若有纰漏望各位指正。
被埋没的志向——文字环绕
回忆一下我们一般什么时候会想用浮动呢?是多列布局还是多列布局呢:)?其实它向往的却是这个
它想干的就是这个——文字环绕,而且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>
(由于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>
当设置浮动后,虽然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>
头痛的开始——基于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的失效有可能会引起垂直方向上的移动。
<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
文字环绕很明显就是活生生地把文字向两边挤,为"大哥"留下个位置,而且小弟们不要走太远,必须时刻拥护着大哥。那大哥是如何圈住小弟们的呢?那得借助外力——line box。文字是以字形(glyph)的形式渲染,和它同一行的inline-level boxes均位于同一个line box中。而line box可谓是夹在containing block和浮动盒子之间勉强生存。
<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吗?》)
<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|right
或position:absolute|fixed
或display:inline-block|table-cell|table|table-caption
或overflow: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>
是"浮动闭合"还是"清除浮动"?
我想各位都看过各种版本的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>
简单地说就是float:left
用clear:left
来清除,float:right
用clear: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>
.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个奇妙的地方:
- 通过
display:table
让即使content为空白时,也能独占据一行,且高度为0;(原理是display:table
会生成一个block-level box包裹着伪元素after) - 通过伪元素
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
我们仅能得到要么图片靠左要么图片靠右的文字环绕效果,那如果我们希望得到如下的四周环绕的效果呢?
虽然已有案例是通过absolute positioning模拟出类似的效果,但布局排版固定导致无法适应大部分场景。如果有个float:both
属性值那该多好啊!另外大家是否觉得以下的环绕效果更有艺术范呢?
听说通过CSS3的shapes特性可以实现四周环绕和上面非四四方方的环绕效果,日后好好研究研究!
2016/04/19补充-参考《CSS网站布局实录-基于Web标准的网站设计指南(第2版)》的5.2.2 不规则文字环绕
<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 特性
那些年我们一起清除过的浮动
如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!
关注 - 85
粉丝 - 707
» 下一篇:CSS魔法堂:小结一下Box Model与Positioning Scheme
【推荐】加入腾讯云自媒体扶持计划,免费领取域名&服务器
· 兴趣降温 安卓厂商无意模仿iPhone X推出3D识别
· 乐视云更名新乐视云联:仍未获云服务牌照
· 微软搜索引擎Bing改进航班 电影和比赛结果查询
· 彭博商业周刊:硅谷悄然掀起中国技术人员回国潮
· 英特尔宣布为2018平昌冬奥会提供VR赛事直播技术
» 更多新闻...
· 以操作系统的角度述说线程与进程
· 软件测试转型之路
· 门内门外看招聘
· 大道至简,职场上做人做事做管理
» 更多知识库文章...
公告
作品:
iScheme—Scheme解释器
CSS魔法堂:说说Float那个被埋没的志向相关推荐
- CSS魔法堂:你一定误解过的Normal flow
前言 刚接触CSS时经常听到看到一个词"文档流",那到底什么是"文档流"呢?然后会看到"绝对定位和浮动定位能脱离文档流",从这句可以看到文 ...
- CSS魔法堂:深入理解line-height和vertical-align
前言 一直听说line-height是指两行文本的基线间的距离,然后又说行高等于行距,最近还听说有个叫行间距的家伙,@张鑫旭还说line-height和vertical-align基情四射,贵圈真乱啊 ...
- CSS魔法堂:hasLayout原来是这样!
前言 过去一直听说旧版本IE下很多诡异bug均由一个神秘角色引起的,那就是hasLayout.趁着最近突然发神经打算好好学习CSS,顺便解答多年来的疑惑. hasLayout到底是何方神圣? hasL ...
- CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins
前言 盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑.本文尝试全面叙述块级.行级盒子模型的特性.作为近日 ...
- CSS魔法堂:重拾Border之——图片作边框
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
- CSS魔法堂:更丰富的前端动效by CSS Animation
前言 在<CSS魔法堂:Transition就这么好玩>中我们了解到对于简单的补间动画,我们可以通过transition实现.那到底多简单的动画适合用transtion来实现呢?答案就是 ...
- CSS魔法堂:重拾Border之——更广阔的遐想
前言 当CSS3推出border-radius属性时我们是那么欣喜若狂啊,一想到终于不用再添加额外元素来模拟圆角了,但发现border-radius还分水平半径和垂直半径,然后又发现border-t ...
- CSS魔法堂:那个被我们忽略的outline
前言 在CSS魔法堂:改变单选框颜色就这么吹毛求疵!中我们要模拟原生单选框通过Tab键获得焦点的效果,这里涉及到一个常常被忽略的属性--outline,由于之前对其印象确实有些模糊,于是本文打算对其 ...
- CSS魔法堂:那个被我们忽略的outline 1
前言 在CSS魔法堂:改变单选框颜色就这么吹毛求疵!中我们要模拟原生单选框通过Tab键获得焦点的效果,这里涉及到一个常常被忽略的属性--outline,由于之前对其印象确实有些模糊,于是本文打算对其 ...
最新文章
- python【力扣LeetCode算法题库】13- 罗马数字转整数
- 摆脱阅读黑洞,退订RSS
- JAVA编码规约(阿里)
- 水果电池打造柠檬电动汽车!
- 近世代数--有限交换群--存在子群的阶是群阶的因子
- junit4/5 getDefaultClassLoader()Ljava/lang/ClassLoader;
- java异常捕获的一点感悟
- Java 的面向接口编程
- Nginx 架构详解
- java控制面板作用_大师为你分析win7系统打开java控制面板的方法
- 小程序 — 保存图片到手机相册①
- NLP知识包--语义分析-语义角色标注
- Google Adsense的技巧、诀窍和秘密
- 2021年下半年软考真题软件设计师真题答案(下午题)
- Badboy 安装 使用 常见问题 badboy当前页面脚本发生错误
- 五大常用百度高级搜索语法
- ArcToolbox工具名英汉对应
- 区分触摸屏种类的几种方法
- 《火车头采集器采集网页数据》火车头配置规则采集信息文章数据。
- 组合导航(一):定位技术分类与介绍
热门文章
- 工业互联网工信部苗圩谈-谋定研究:对话中国经济和信息化
- 跨界巨头谋定现代农业-农民丰收节交易会:全产业链布局
- 第二周 第七节 列表的使用
- 11组软件工程组队项目失物招领系统——进度汇报和下周目标
- Mac androidStudio cannot resolve corresponding JNI function
- POJ 2785 4 Values whose Sum is 0
- EF optimize the perfermance
- Uva10294 Arif in Dhaka (置换问题)
- 关于js中namespace命名空间模式
- 沟通篇:产品经理如何与UI进行沟通