『面试的经历』—— 四年前端在CSS面试上跪了的后续

5,652 阅读4分钟

一、前言

我也没想到四年前端在CSS面试上跪了/(ㄒoㄒ)/~~这篇文章会被诸多公众号转载,有小伙伴在留言提问,我归纳了一下在这里做个更详细的讲解。另外转载的麻烦注明一下文章来源,其他的不介意,知识是要传播的。觉得好的,点个赞,让更多人看到。

二、同一个BFC的两个相邻块级元素的margin会发生重叠的疑问

<body>
    <div style="width:100px;height:100px;background:red;margin:20px;"></div>
    <div style="width:100px;height:100px;background:blue;margin:20px;"></div>
</body>

根据BFC的渲染规则之一:块级元素垂直方向的距离由margin决定。属于同一个BFC的两个相邻块级元素的margin会发生重叠。

有的小伙伴这么理解成:在同一个BFC容器中会发生重叠,那么只要不在一个BFC容器中就不会发生重叠。

<body>
    <div>
        <div style="width:100px;height:100px;background:red;margin:20px;"></div>
        <div style="width:100px;height:100px;background:blue;margin:20px;"></div>
    </div>
</body>

在外面包一个div元素,div元素不是一个BFC容器,两个div元素就不在一个BFC容器中。结果在浏览器渲染的结果,还是margin重叠。

我先引用一段W3C的译文

在普通流中的Box(框)属于一种 formatting context(格式化上下文),类型可以是BFC(块格式化上下文),或者是IFC(行内格式化上下文),但不能同时属于这两者。并且Block boxes(块框)在 BFC(块格式化上下文)里格式化,Inline boxes(块内框) 则在IFC(行内格式化上下文) 里格式化。任何被渲染的元素都生成一个boxes,并且不是Block boxes,就是Inline boxes。即使是未被任何元素包裹的文本,根据不同的情况,也会生成匿名的 Block boxes或者Inline boxes。

上面的描述可以理解为:把所有的元素都扔到对应的FC(formatting context)里格式化。

那么你有没有想过,有没有元素不属于任何一种FC?

//代码一
<div style="overflow:hidden">
    <div></div>
</div>

毫无疑问的是,上面代码中内层div属于外层div创建的BFC,那么外层div呢?属于那种FC。再来看代码二。

//代码二
<div>
    <div></div>
</div>

那上面代码中内层div和外层div孤零零的,又是属于那种FC。

这时候是不是有点懵,别懵,BFC触发条件之一:根元素html来救场。

那么代码一中的内层div属于外层div创建的BFC,外层div属于根元素html创建的BFC。

代码二中的内层div和外层div都属于根元素html创建的BFC。

回过来再看开始的代码

<body>
    <div>
        <div style="width:100px;height:100px;background:red;margin:20px;"></div>
        <div style="width:100px;height:100px;background:blue;margin:20px;"></div>
    </div>
</body>

上面外层div不是BFC,那么两个内层div还是属于根元素html创建的BFC,那还是在同一个BFC下,margin仍是重叠的。

总之一句话,如果元素的父级不是BFC或者IFC,那么就会去找父级的父级,直到找到触发BFC或者IFC的元素。(FFC先别在这边讨论)

三、关于用overflow:hidden触发不了body元素BFC的疑问

先引用一段w3c对BFC定义的原文

Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

里面描述了如果overflow不是visible的块级元素将创建BFC。

但是要注意里面有这么一句话** except when that value has been propagated to the viewport** 可翻译为 除非该值已经扩散到了视口

然后我们先看overflow的w3c定义的原文

UAs must apply the 'overflow' property set on the root element to the viewport. When the root element is an HTML "HTML" element or an XHTML "html" element, and that element has an HTML "BODY" element or an XHTML "body" element as a child, user agents must instead apply the 'overflow' property from the first such child element to the viewport, if the value on the root element is 'visible'. The 'visible' value when used for the viewport must be interpreted as 'auto'. The element from which the value is propagated must have a used value for 'overflow' of 'visible'.

对其翻译一下

  • UAs需要将根元素上的overflow属性置于视口之上。
  • overflow扩散行为:当根元素是html元素且overflow为visible,而且html元素有body作为其子元素,UAs则需要将第一个body之上的overflow属性应用于视口。
  • 用于视口的overflow: visible将被解析为overflow: auto。
  • overflow扩散行为将导致body的overflow属性为visible。

看到这里,小伙伴应该有的明白了吧。

html元素的overflow默认属性是visible,导致body元素的overflow:hidden被应用于视口,导致body元素的overflow属性最终为visible,因此body没有触发BFC。

所以只能先将html元素的overflow属性设置为hidden,再把body元素的overflow属性设置为hidden,才能使body触发BFC 。