Two-Column Layout 与 Block Formatting Context

发布时间: 2017-01-02 10:07:17 作者: 大象笔记

在临摹 semantic-ui 的 feed 实现时,发现我对 Two-Column Layout 的实现并没有掌握。

这是我第一次做出来的效果

而我想要的效果是这样的

双栏布局不就是加个 float: left 这么简单么?看起来并没有这么简单,我之前用 placehold.it 图片来模拟 div float 布局,看来是忽略了很多隐藏的问题。

Google 了一下,原来只需要在右侧 div 加上 overflow: hidden 即可。

WTF,overflow: hidden 与 float 布局有什么关系

我印象中,这应该不是第一次查到这么诡异的 CSS 解决方案了。如果是之前,我基本上解决之后就不管了。奈何现在写模板的机会越来越多,所以还是有必要深究一下。

overflow: hidden 是黑科技,为其对应的 box 创建了一个全新的 block formatting context (BFC)。而 block formatting context 会改变原有的布局策略。

Block Formatting Context 是什么?

如果一上来就想直接弄明白什么是 Block Formatting Context, 实际上很有难度。我元旦晚上一边看《机械师2》一边查的资料,整整理解了一个半小时,仍然对很多概念很模糊。最科学的方法是完整的看一遍 W3C Visual formatting model

不过这样一来就比较枯燥了,所以我还是最终选择了乱翻的阅读策略,遇到看不懂的再查。

看一下 W3C 的解释

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.

In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.

In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).

看完这三段,虽然各种疑问,但是有一点是明确的,加了 overflow: hidden 之后,对应的 div 创建了一个新的 Block Formatting Context。而在 Block Formatting Context 中,每个 box 的左边都会触及 container 的左边,这样就解决了我遇到的右侧 div 中内容上下不对其的情况。

但是,我产生了几个疑问

第一个问题,显然最外层的 div 并不符合 Block Formatting Context 的定义。那么还有哪些类似 BFC 的排版规则。CSS 2.1 中,box 的布局遵循三种 positioning scheme

还原案发现场

利用学到的新知识还原一下案发现场

<div class="container">
  <div class="avatar"></div>
  <div class="main">
    <p class="author"></p>
    <p class="comment"></p>
  </div>
</div>

首先,main div 参与了 normal flow 的布局,左边与 container 的左边重合。而 avatar 参与了 floats 布局,也与 container 的左边重合。这样 container 中的 author, comment 部分就被挤到了 avatar 的右侧。但是需要注意的是,main 的左边依然是与 container 的左边是重合的。所以当 comment 内容过长时,就会出现与 container 左边零距离的情况。

解决方案就是使 author, comment 的左边紧贴 main 的左边,所以加上 overflow: hidden 使其变成新的 BFC, 这样 main 的子元素就能保证左边与其左边零距离了。于是,main 就不得不远离 container 的左边。

用人话来说就是,构成新 BFC 之后,就不会与平级的 float box overlap 了

overflow: hidden 是最好的解决方案么

如果是使用 float 进行排版布局,这的确是最好的解决方案。但是,能明显看出,float 诞生的原始初衷并不是用来进行双栏、多栏布局的,否则就不需要这种可读性为零的黑科技了。也许,只有 table 是天生用来进行多栏布局的,但是,实战中,大家发现还是 float 的布局效果更佳,所以宁愿抛弃可读性,也不愿意使用 table。

但是,这种的代码太恶心了。还是有必要学习一下 flex box 的布局方式,这说明 bootstrap 4 采用 flex box 是有道理的。

参考

我是一名山东烟台的开发者,联系作者