使用FLEX实现一种上下高度不固定的自适应布局
发布日期:2019-12-22文章字数:1.3K
此布局的需求是:头部高度不固定,由子元素撑高,中间内容高度不固定,自动填满父容器剩余高度,底部高度固定。
这种布局是下面这种布局的变种:
头部和中间内容都变成了不固定的,一般用于后台管理系统,上部分是一些查询条件和操作按钮,查询条件个数不固定,中间部分是表格内容,底部一般用于分页,固定高度。
此种布局用flex可以很容易的实现:父容器设置高度为100%,flex-direction设置为column(主轴设置为竖向),上部flex-shrink设置0,下部flex-grow设置1,底部flex-shrink设置0。
CSS部分:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
}
.wrapper {
height: 100%;
padding: 10px;
display: flex;
flex-direction: column;
}
.head {
border: 1px solid red;
padding: 15px;
flex-shrink: 0;
margin-bottom: 10px;
}
.content {
border: 1px solid blue;
flex: 1;
padding: 15px;
margin-bottom: 10px;
line-height: 50px;
overflow: auto; //此行是关键
}
.foot {
flex-shrink: 0;
padding: 10px;
border: 1px solid green;
}
HTML部分:
<div class="wrapper">
<div class="head">
<p>子元素</p>
<p>子元素</p>
<p>子元素</p>
<p>子元素</p>
</div>
<div class="content">
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
<p>内容</p>
</div>
<div class="foot">
<p>底部</p>
</div>
</div>
中间的内容用来放element-ui的表格,表格高度设置为100%,可以达到固定表头内容滚动的效果,一切看起来都很美好。
然而最近我重装了一次系统然后把chrome升级到79版本后,发现一个蛋疼的事情,这种方式居然失效了,出现了下面的情况:
中间的内容高度设置失效了,也变成了由子元素撑高。起初我怀疑是element-ui的锅,然后换了不同版本的element-ui后还是如此,然后我又怀疑可能是node版本的问题,因为我重装系统后把node由v8换成了v10,当我切换成v8后还是如此。后来我在同事的电脑上查看,他们居然没有出现这种情况,问题到底出现在了哪里?经过仔细排查后,这个锅最终落在了chrome头上,当我把chrome装回78版本后,一切又变得正常了。
然后我发现这个问题也在firefox上面出现了,这种布局似乎只能在chrome78及以下生效(IE11也生效)。然而我不能阻止用户把chrome升级到79版本或使用firefox浏览器,所以这个问题的根源也不在chrome或firefox,一定是别的什么地方出现了问题。
最终问题定位到了BFC(块格式化上下文,Block Formatting Context)上面,关于BFC的概念你可以前往MDN查看。
问题的关键就是要为page-body为这个div创建BFC,让它里面的元素不会影响到外面的元素,下列方式会创建块格式化上下文:
根元素(<html>)
浮动元素(元素的 float 不是 none)
绝对定位元素(元素的 position 为 absolute 或 fixed)
行内块元素(元素的 display 为 inline-block)
表格单元格(元素的 display为 table-cell,HTML表格单元格默认为该值)
表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)
匿名表格单元格元素(元素的 display为 table、table-row、 table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 inline-table)
overflow 值不为 visible 的块元素
display 值为 flow-root 的元素
contain 值为 layout、content或 paint 的元素
弹性元素(display为 flex 或 inline-flex元素的直接子元素)
网格元素(display为 grid 或 inline-grid 元素的直接子元素)
多列容器(元素的 column-count 或 column-width 不为 auto,包括 column-count 为 1)
column-span 为 all 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中(标准变更,Chrome bug)。
不过我试了多种方式,都没有生效,只有设置 overflow: auto
之后才生效。
这个问题的根本原因就是浏览器创建BFC的规则不一致,chrome78以下版本和IE11会为display
为flex
的直接子元素创建BFC,不管这个子元素的overflow值为什么(默认值为visible), chrome79版本及firefox则不会,只有设置 了overflow: auto
之后才会创建BFC,不确定这是chrome79的feature还是bug。