第6章 流的破坏与保护
# 第6章 流的破坏与保护
# 魔鬼属性float
# float的本质与特性
float浮动属性让父元素高度坍塌的原因就是为了实现文字环绕效果。
float自身特性:
- 包裹性;
- 块状化并格式化上下文;
- 破坏文档流;
- 没有任何
margin合并。
包裹性,由包裹和自适应性两部分组成。
- 包裹。浮动元素父元素宽度
200px,子元素是一个宽度128px宽度的图片,则此时浮动元素宽度表现为包裹,就是里面图片的宽度128px。

- 自适应性。
块状化,元素一旦float的属性值不为none,则其display计算值为block或table。text-align对浮动元素无效。
| 设定值 | 计算值 |
|---|---|
inline | block |
inline-block | block |
inline-table | table |
table-row | block |
table-row-group | block |
table-column | block |
table-columngroup | block |
table-cell | block |
table-caption | block |
table-header-group | block |
table-footer-group | block |
# float的作用机制
文字环绕效果是由两个特性(父级高度坍塌和行框盒子区域限制)共同作用的结果,定高只能解决父级元素高度坍塌带来的影响,但是对行框盒子区域限制没有任何效果,结果导致的问题是浮动元素垂直区域一旦超出高度范围,或下面元素margin-top负值上偏移,就很容易使后面的元素发生“环绕效果”。
# float更深入的作用机制
浮动元素和内联元素在一行显示。
- 浮动锚点是
float元素所在的流中的一个点,这个点本身并不浮动。其作用是产生行框盒子,因为浮动锚点表现如同一个空的内联元素,有内联元自然就有行框盒子。 - 浮动参考指的是浮动元素对齐参考的实体。
float元素的浮动参考是行框盒子,也就是float元素在当前行框盒子内定位。
# float与流体布局
See the Pen 中间内容居中的左中右布局 by whjin (@whjin) on CodePen.
# float的天然克星clear
# 什么是clear属性
clear专门用来处理float属性带来的高度坍塌等问题。
clear: none | left | right | both
none:默认值,左右浮动left:左侧抗浮动right:右侧抗浮动both:两侧抗浮动
实际应用中只使用clear:both;即可。
# 成事不足败事有余的clear
clear属性只有块级元素才有效,而:after等伪元素默认都是内联水平,这就是伪元素清除浮动影响时需要设置display属性值的原因。
clear:both的作用本质是让自身不与float元素在一行显示,并不是真正意义上的清除浮动。
- 如果
clear:both;元素前面的元素就是float元素,则margin-top负值即使设成-9999px,也没有效果。 clear:both;后面的元素依旧可能发生文字环绕的现象。
# CSS世界的结界——BFC
# BFC的定义
BFC称为块级格式化上下文。BFC元素不可能发生margin重叠,margin重叠会影响外面的元素;BFC元素也可以用来清除浮动的影响,如果不清楚,子元素浮动则会父元素高度坍塌,必然会影响后面元素布局和定位。
何时会触发BFC,常见情况如下:
html根元素;overflow的值为auto、scroll或hidden;display的值为table-cell、table-caption和inline-block中的任何一个;float的值不为none;position的值不为relative和static。
只要元素符合上面任意一个条件,就无须使用clear:both;属性去清除浮动的影响。
# BFC与流体布局
BFC的表现原则:具有BFC特性的元素的子元素不会受到外部元素的影响,也不会影响外部元素。普通流体元素在设置了overflow:hidden;后,会自动填满容器中除了浮动元素以外的剩余空间,形成自适应布局效果。
img {
float: left;
margin-right: 10px;
}
.content {
overflow: hidden;
}
基于BFC特性的自适应布局有如下优点:
- 自适应内容由于封闭更加健壮,容错性更强。内部设置
clear:both;不会与float元素相互干扰而导致错位。 - 自适应内容自动填充浮动以外区域,无需关心浮动元素宽度,可以整站大规模应用。
.left {
float: left;
}
.right {
float: right;
}
.bfc {
overflow: hidden;
}
float:left;。浮动元素本身BFC化,然而浮动元素具有破坏性和包裹性,失去了元素本身的流体自适应性,因此无法用来实现自动填满容器的自适应布局。position:absolute;。脱离文档流,不容易操作。overflow:hidden;块状元素的流体特性保存得很好,加上BFC的独立区域特性,而且从IE7开始就支持,兼容性很好。唯一的问题是容器盒子外的元素可能会被隐藏掉。display:inline-block;display:table-celldisplay:table-rowdisplay:table-caption
总结上面的自适应布局设置,最佳实践如下:
overflow: auto/hidden;,适用于IE7及以上版本浏览器;display: inline-block;,适应于IE6和IE7;display: table-cell;,适用于IE8及以上版本浏览器。
IE7及以上版本浏览器适配的自适应解决方案:
- 借助
overflow属性,如下:
.lbf-content {
overflow: hidden;
}
- 融合
display: table-cell;和display: inline-block;,如下:
.lbf-content {
display: table-cell;
width: 9999px;
}
display: table-cell;元素内连续英文字符无法换行的问题:
.word-break {
display: table;
width: 100%;
table-layout: fixed;
word-break: break-all;
}
# 最佳结界overflow
要彻底清除浮动的影响,最适合的属性是
overflow。overflow:hidden;声明不会影响元素原先的流体特性或宽度表现。
# overflow裁剪界线border box
当子元素内容超出容器宽度高度限制的时候,剪裁的边界是border box的内边缘,而非padding box的内边缘。
在实际项目开发时,要尽量避免滚动条容器设置padding-bottom值。
# 了解overflow-x和overflow-y
IE8以上浏览器,overflow增加了两个属性,overflow-x和overflow-y,分别表示单独控制水平或垂直方向上的剪裁规则。
支持的属性值和overflow属性一模一样:
visible:默认值hidden:剪裁scroll:滚动条auto
不会出现一个方向溢出剪裁或滚动,另一个方向内容溢出显示的效果。
# overflow与滚动条
浏览器的滚动条:
- 默认滚动条来自
html,而不是body标签。去除页面默认滚动条:
html {
overflow: hidden;
}
在PC端,滚动条高度可以使用document.documentElement.scrollTop获取,但是在移动端,需要使用document.body.scrollTop获取。
2. 滚动条会占用容器的可用高度或宽度。
让页面滚动条不发生晃动的技巧
html {
overflow-y: scroll;
}
:root {
overflow-y: auto;
overflow-x: hidden;
}
:root body {
position: absolute;
}
body {
width: 100%;
overflow: hidden;
}
滚动条自定义效果:
- 整体部分:
::-webkit-scrollbar - 两端按钮:
::-webkit-scrollbar-button - 外层轨道:
::-webkit-scrollbar-track - 内层轨道:
::-webkit-scrollbar-track-piece - 滚动滑块:
::-webkit-scrollbar-thumb - 边角:
::-webkit-scrollbar-corner
::-webkit-scrollbar { /*血槽宽度*/
width: 8px;
height: 8px;
}
::-webkit-scrollbar-thumb { /*拖动条*/
background-color: rgba(0, 0, 0, .3);
border-radius: 6px;
}
::-webkit-scrollbar-track { /*背景槽*/
background-color: #ddd;
border-radius: 6px;
}
# 依赖overflow的样式表现
单行文字溢出...效果,需要使用到overflow:hidden;、text-overflow:hidden;,效果实现必需的3个声明如下:
.ell {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
最多显示2行内容,再多就打点的核心CSS代码:
.ell-rows-2 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
# overflow与锚点定位
基于URL地址的锚链location.hash实现锚点跳转的方法有两种:
a标签以及name属性- 使用标签的
id属性
<a href="#1">发展历程</a>
<a name="1"></a>
1. 锚点定位行为的触发条件
- URL地址中的锚链与锚点元素对应并有交互行为;
- 可
focus的锚点元素处于focus状态。
focus锚点定位指的是类似链接或按钮、输入框等可以被focus的元素在被focus时发生的页面重定位现象。
URL地址锚点定位是让元素定位在浏览器窗体的上边缘,而``focus锚点定位是让元素在浏览器窗体范围内显示即可。
2. 锚点定位作用的本质
锚点定位行为的发生,本质上是通过改变容器滚动高度或宽度来实现。改变了scrollTop或scrollLeft的值。
See the Pen 窗体无跳动选项卡 by whjin (@whjin) on CodePen.
处理列表部分区域正在浏览器外面依然会跳动的问题:
$('label.click').removeAttribute('for').on('click', function () {
$('.box').scrollTop(xxx);//滚动数值
});
基于父容器自身的scrollTop值改变来实现自定义滚动条效果。
- 实现简单,无须做边界判断。
container.scrollTop=99999;,列表滚动就是scrollTop值,实时获取。 - 可与原生的
scroll事件天然继承,无缝对接。 - 无须改变子元素的结构。
# float的兄弟position:absolute
绝对定位absolute具有块状化,块状格式化上下文、包裹性和自适应性。自适应性的最大宽度由“包含块”决定。
# absolute的包含块
普通元素的百分比宽度是相对于父元素的content box宽度计算,而绝对定位元素的宽度是相对于第一个position不为static的祖先元素计算的。
- 根元素
html被称为“初始包含块”,其尺寸等同于浏览器可视窗口的大小。 - 对于其他元素,如果该元素的
position是relative或static,则“包含块”由其最近的块容器祖先盒子的content box边界组成。 - 如果元素
position:fixed;,则“包含块”是“初始包含块”。 - 如果元素
position:absolute;,则“包含块”由最近的position不为static的祖先元素建立,具体方式如下: 如果该祖先元素是纯inline元素,则规则略复杂:- 给内联元素的前后各生成一个宽度为
0的内联盒子,则这两个内联盒子的padding box外面的包围盒子就是内联元素的“包含块”。 - 如果该内联元素被跨行分割,则包含块是未定义的。
否则,“包含块”由该祖先的
padding box边界组成。
- 给内联元素的前后各生成一个宽度为
和常规元素相比,绝对定位元素的包含块有3个明显的差异:
- 内联元素也可以作为包含块所在的元素;
- 包含块所在的元素不是父级块元素,而是最近的
position不为static的祖先元素或根元素; - 边界是
padding box而不是content box。
内联元素的“包含块”是由“生成的”前后内联盒子决定,与里面的内联盒子细节没有任何关系。
height:100%;是第一个具有定位属性值得祖先元素的高度,而height:inherit;则是单纯的父元素的高度继承。
# 具有相对特性的无依赖absolute绝对定位
1. 各类图标定位
See the Pen 无依赖绝对定位”与导航图标定位 by whjin (@whjin) on CodePen.
See the Pen 文字和图片水平对齐 by whjin (@whjin) on CodePen.
2. 超越常规布局的排版
See the Pen “无依赖绝对定位”与超越常规布局的排版 by whjin (@whjin) on CodePen.
3. 下拉列表的定位
See the Pen “无依赖绝对定位”与下拉列表定位 by whjin (@whjin) on CodePen.
4. 占位符效果模拟
5. 进一步深入“无依赖绝对定位”
# absolute与text-align
absolute元素的display计算值是块状的,text-align不会起作用。
See the Pen absolute与text-align互相作用 by whjin (@whjin) on CodePen.
See the Pen 主结构右外侧固定定位 by whjin (@whjin) on CodePen.
# absolute与overflow
如果overflow不是定位元素,同时绝对定位元素和overflow容器之间也没有定位元素,则overflow无法对absolute元素进行裁剪。overflow元素父级是定位元素也不会裁剪。
overflow属性所在的元素同时也是定位元素,里面的绝对定位元素会被裁剪;overflow元素和绝对定位元素之间有定位元素,也会被裁剪。overflow属性值不是hidden,而是auto或scroll,即使绝对定位元素高度比overflow元素高度大,也不会出现滚动条。
# absolute与clip
clip属性要起作用,元素必须是绝对定位absolute或固定定位fixed。
clip属性语法:clip: rect(top right bottom left)
# 重新认识的clip属性
1. fixed固定定位的剪裁
.fixed-clip {
position: fixed;
clip: rect(30px 200px 200px 20px);
}
2. 最佳可访问性隐藏
最佳可访问性隐藏指的是视觉上看不见,但是辅助设备能够进行识别和访问。
.logo h1 {
position: absolute;
clip: rect(0 0 0 0);
}
<a href="/" class="logo">
<h1>我是标题</h1>
</a>
# 深入了解clip的渲染
clip隐藏仅仅是决定了哪部分是可见的,非可见部分无法响应点击事件,虽然视觉上隐藏,但是元素的尺寸依旧是原来的尺寸。
# absolute的流体特性
# 当absolute遇到left/top/right/bottom属性
当absolute遇到left/top/right/bottom属性时,absolute元素才真正变成绝对定位元素。
# absolute的流体特性
当一个绝对定位元素,其对立定位方向属性同时具有定位数值时,就会发生流体特性。
普通元素流体特性只有水平方向(默认),但是绝对定位元素可以让垂直方向和水平方向同时保持流动性。
# absolute的margin:auto居中
.box {
width: 200px;
height: 200px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
# position:relative才是大哥
# relative对absolute的限制
# relative与定位
relative与定位特性:一是相对自身,二是无侵入(当relative进行定位偏移时,不会影响周围元素的布局)。
relative定位:相对定位元素的left/top/right/bottom百分比值是相对于 包含块计算,而非自身。
top/bottom垂直方向的百分比值计算和height百分比值一样,都是相对于高度计算。
当相对定位元素同时应用对立方向定位值,top/bottom和left/right同时使用时,其表现和绝对定位差异很大,只有一个方向的定位属性起作用。
# relative的最小化影响原则
- 尽量不适用
relative,定位某元素,可以使用无依赖的绝对定位; - 如果需要使用
relative,则该relative需要最小化。
<div>
<div style="position:relative;">
<img src="1.jpg" alt="" style="position: absolute;top: 0;right: 0;">
</div>
<p>内容1</p>
<p>内容2</p>
</div>
# 强悍的position:fixed固定定位
# position:fixed不一样的“包含块”
position:fixed固定定位元素的包含块是根元素。唯一可以限制固定定位元素的是<html>根元素。relative对fixed定位没有任何限制作用。
See the Pen 无依赖固定定位 by whjin (@whjin) on CodePen.
# position:fixed的absolute模拟
<div class="page">固定定位元素</div>
<div class="fixed"></div>
html, body {
height: 100%;
overflow: hidden;
}
.page {
height: 100%;
overflow: auto;
}
.fixed {
position: absolute;
}