本文的起因是团队现在处于缺人的阶段, 最近开始帮忙进行电话面试的操作. 面了不少了, 有不少收获, 其中最大的还是对自己的警惕作用. 虽然是自己在面试别人, 但也发现, 很多在交流过程中涉及到的内容, 自己虽然都知道或者有了解, 但是要系统或者清晰的描述出来其实是不容易的, 所以开始整理一些看似都懂的一些 "乱七八糟" 的知识.
[本文主要是根据参考资料整理以及一些自己的理解, 参考资料已在文末列出.]
浮动是一个 CSS 布局中的经典属性, 用过浮动的小伙伴肯定会遇到需要清除浮动或者说闭合浮动的情况. 我对清除还是闭合的理解是, 看你的实现方法来说.
简单来说, 使用 clear 属性来实现可以认为是清除浮动(clearing float), 是元素生成 BFC 或者 hasLayout 的方法可以称之为闭合浮动(enclosing float).
CSS 中的定位机制可以分为:
普通流(俗称文档流, 但是标准里面为 normal flow, 所以称之为普通流比较合理).
浮动: 引用一丝姐姐的文章中的话如下, 需要注意的点是浮动框会一直浮动到包含框或者另一个浮动框为止, 并且浮动的元素是脱离普通流的, 脱离了之后只会影响普通流中的内联元素的布局, 对于块级元素没有影响, 就像这个浮动元素不存在一样. 同时, 有可能会出现 "高度塌陷" 的情况(这也是清除 & 闭合浮动需求的主要场景).
浮动的框可以左右移动, 直至它的外边缘遇到包含框或者另一个浮动框的边缘. 浮动框不属于文档中的普通流, 当一个元素浮动之后, 不会影响到块级框的布局而只会影响内联框 (通常是文本) 的排列, 文档中的普通流就会表现得和浮动框不存在一样, 当浮动框高度超出包含框的时候, 也就会出现包含框不会自动伸高来闭合浮动元素("高度塌陷" 现象).
绝对定位: 不是本文的重点, 就不多说了. 简单来说, 绝对定位的元素是脱离普通流的, 相对于最近的 display 属性为非 static 的父级元素定位.
闭合浮动
闭合浮动的本质就是让元素产生 BFC 或者 hasLayout 属性为 true.
BFC 的创建方法(参考自 Block formatting context MDN), 加粗的为常见或者需要注意的方法:
the root element or something that contains it
- floats (elements where float is not none)
- absolutely positioned elements (elements where position is absolute or fixed)
- inline-blocks (elements with display: inline-block)
- table cells (elements with display: table-cell, which is the default for html table cells)
- table captions (elements with display: table-caption, which is the default for HTML table captions)
- anonymous table cells implicitly created by the elements with display: table, table-row, table-row-group, table-header-group, table-footer-group (which is the default for HTML tables, table rows, table bodies, table headers and table footers, respectively), or inline-table
- block elements where overflow has a value other than visible
- display: flow-root
- elements with contain: layout, content, or strict
- flex items (direct children of the element with display: flex or inline-flex)
- grid items (direct children of the element with display: grid or inline-grid)
- multicol containers (elements where column-count or column-width is not auto, including elements with column-count: 1)
- column-span: all should always create a new formatting context, even when the column-span: all element isn't contained by a multicol container (Spec change, Chrome bug).
对于 hasLayout 属性, 一丝的文章中:
IE6-7 的显示引擎使用的是一个称为布局 (layout) 的内部概念, 由于这个显示引擎自身存在很多的缺陷, 直接导致了 IE6-7 的很多显示 bug. 当我们说一个元素 "得到 layout", 或者说一个元素 "拥有 layout" 的时候, 我们的意思是指它的微软专有属性 hasLayout http://msdn.microsoft.com/worksh ... rties/haslayout.asp 为此被设为了 true .IE6-7 使用布局的概念来控制元素的尺寸和定位, 那些拥有布局 (have layout) 的元素负责本身及其子元素的尺寸设置和定位. 如果一个元素的 hasLayout 为 false, 那么它的尺寸和位置由最近拥有布局的祖先元素控制.
简单来说, 就是旧版本 IE 特有的一个控制布局的概念, 对于我们来说要考虑的是在处理 IE 的兼容性的时候需要留意这个属性, 从表现上来说, 可以将 hasLayout 等同于 BFC 来考虑.
触发 hasLayout 的条件:
- position: absolute
- float: left|right
- display: inline-block
width: 除 "auto" 外的任意值
height: 除 "auto" 外的任意值 (例如很多人闭合浮动会用到 height: 1% )
zoom: 除 "normal" 外的任意值 (MSDN) http://msdn.microsoft.com/worksh ... properties/zoom.asp
writing-mode: tb-rl (MSDN) http://msdn.microsoft.com/worksh ... ies/writingmode.asp
在 IE7 中, overflow 也变成了一个 layout 触发器:
- overflow: hidden|scroll|auto ( 这个属性在 IE 之前版本中没有触发 layout 的功能. )
- overflow-x|-y: hidden|scroll|auto (CSS3 盒模型中的属性, 尚未得到浏览器的广泛支持. 他们在之前 IE 版本中同样没有触发 layout 的功能)
这么多的触发条件, 其实需要记住的就是: 最无害和被大家用来处理旧版本 IE 闭合浮动兼容性的是 zoom.
BFC
对于为什么触发了 BFC 可以实现闭合浮动的效果, 从 BFC 的定义来看:
A block formatting context contains everything inside of the element creating it that is not also inside a descendant element that creates a new block formatting context.
简单来说, BFC 的一个最重要的效果是, 让处于 BFC 内部的元素与外部的元素相互隔离, 使内外元素的定位不会相互影响, 这是利用 BFC 清除浮动所利用的特性.
此外 BFC 的特性主要的可以记住以下几点:
内部的盒会在垂直方向一个接一个排列, 也就是 BFC 内部是一个普通流;
处于同一个 BFC 中的元素相互影响, 可能会发生 margin collapse;[防止上下 margin collapse 问题]
每个元素的 margin box 的左边, 与容器块 border box 的左边相接触(对于从左往右的格式化, 否则相反). 即使存在浮动也是如此; BFC 就是页面上的一个隔离的独立容器, 容器里面的子元素不会影响到外面的元素, 反之亦然;
计算 BFC 的高度时, 考虑 BFC 所包含的所有元素, 连浮动元素也参与计算;[解决 "高度塌陷问题"]
浮动盒区域不叠加到 BFC 上;[文本清除浮动, 防止文字环绕效果]
清除浮动
清除浮动用的就是 clear 属性配合 both 属性值了. 可以用额外的元素放到包含块的尾部, 或者使用伪元素设置 clear both 来实现. 个人推荐比较好的方法是使用伪类, 然后配合 IE 的 hasLayout 兼容的方法, 在一丝姐姐的文章中的那个最佳解:
- .clearfix:after {
- content:".";
- display:block;
- height:0;
- visibility:hidden;
- clear:both;
- }
- .clearfix {
- *zoom:1;
- }
另外在一丝的文章的最后提到了 Nicolas Gallagher 的文章中的方法:
- .clearfix: before,
- .clearfix: after {
- content: "";
- display: table;
- }.clearfix: after {
- clear: both;
- }
- /* For IE 6/7 (trigger hasLayout) */
- .clearfix {
- zoom: 1;
- }
这里的重点是这个 before 的伪元素的作用, 效果是处理内部元素的 margin 和上面的外部的元素的 margin 发生叠加的. 我的理解是清除浮动的作用只是在元素的最后通过 clear: both 的方法实现了清除浮动从而消除了高度塌陷这些问题. 但是本质上并没有形成一个 BFC, 也就是不会有 BFC 的其他的一些作用, 比如防止上下 margin collapse 的问题. 这里通过设置一个 before 的的 display 的 table 的元素 (形成 BFC) 来解决顶部 margin collapse 的问题.
参考资料:
那些年我们一起清除过的浮动 http://www.iyunlu.com/view/css-xhtml/55.html
Block formatting context MDN https://developer.mozilla.org/en-US/docs/web/Guide/CSS/Block_formatting_context
学习 BFC (Block Formatting Context)
来源: https://juejin.im/post/5acdc8775188255c3201150b