flex实现CSS经典布局:上中下三行,中间自适应占满 以及在IE10+上的兼容性踩坑

6,754 阅读4分钟

这次的目标是实现一个简单的CSS经典布局,即上中下三行,上下定高,中间自适应占满,这种布局常见于文章正文页,列表页等,上边是导航,中间是内容部分,下边是底部信息栏,包括版权信息等。中间自适应占满保证在中间内容部分高度不够时,底部信息栏不至于提到半腰,十分不美观。

flex确实给前端带来了很多便利,以往实现这种布局,往往都是使用绝对定位或者JS动态调整,虽然也可以实现,但是不够直观,我认为更接近于一种hack,使用flex后,较短的代码就可以实现这个布局,废话不多说,上代码:

HTML部分:

<div class="wrapall">
    <header>我是header</header>
    <main>我是main</main>
    <footer>我是footer</footer>
</div>

CSS部分:

* {
    margin: 0;
    padding: 0;
}

.wrapall {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

header {
    flex: 0 0 auto;
    background-color: pink;
}

main {
    flex: 1 1 auto;
    background-color: aqua;
}

footer {
    flex: 0 0 auto;
    background-color: lightgreen;
}

稍微解释下,在最外层class=wrapall使用display: flex,指定为 flex 布局,并且设置最小高度为100vh,使用flex-direction: column指定主轴为垂直方向,起点在上沿。

之后在header,footer两个项目上使用flex: 0 0 auto,这是一个缩写,相当于flex-grow: 0; flex-shrink:0; flex-basis: auto的简写,表示项目在任何情况下都不放大或缩小,保持项目的本来大小。

之后在中间main这个项目上使用:flex: 1 1 auto,更简短的缩写是flex: auto,相当于flex-grow: 0; flex-shrink:0; flex-basis: auto的简写,表示在空间变化时放大或缩小,并且分配余下的空间。

这样就可以实现我们预期的布局了,这几个项目都设置了背景色,便于区分,在chrome浏览器上显示如下:

可以看到,在中间的项目高度不足时,依然填充了剩余空间。

写到这里,如果不考虑IE兼容性的问题,只使用现代浏览器的情况下,已经没有问题了,如果有IE兼容需求的话,这样的布局IE10+是无法识别的,在IE10打开的显示如下:

可以看到,我们期望的布局并没有实现,我就是在公司的项目踩到了这个坑,最开始一直在考虑是flex兼容性的问题,但是那个项目使用了postcss,并且在CANIUSE上检查flex兼容性,并没有说flex-grow: 1在IE10无效,当时就有点摸不着头脑。

后来意识到,这可能不是flex-grow的问题,而是min-height的问题,研究测试之后发现,在IE10+,flex布局虽然可用,但是最外层的flex布局,即最外层的class=wrapall使用display: flex时,不能同时设置min-height,所以在最外层class=wrapall外再加一层,HTML代码如下:

<div class="wrapall-fixIE">
    <div class="wrapall">
        <header>我是header</header>
        <main>我是main</main>
        <footer>我是footer</footer>
    </div>
</div>

CSS新增代码如下:

.wrapall-fixIE {
    display: flex;
}

.wrapall {
    ...
    width: 100%;
}

即在外层新增一个flex布局节点class=wrapall-fixIE,保证设置min-height的不是最外层flex节点,值得注意的是,需要在之前的最外层class=wrapall设置width为100%,这是由于flex内部的元素并非block,在内容宽度不足的情况下不会占据全部宽度。

这就是flex实现CSS经典布局上中下三行以及兼容IE的全过程了,其实可以同理实现圣杯布局,实现圣杯布局的时候,由于不存在min-height的限制,所以即使在实现IE10+兼容时,也不需要包裹一个class=wrapall-fixIE作为最外层了,但是在IE10上flex项目未必被识别为block元素,所以在项目上添加display: block,可以少踩一些坑。flex确实是个利器,但是兼容IE确实有一点点麻烦,所以人生苦短,抛弃IE吧。

以上,完结撒花~