在最近的一个项目中,我们终于将Flexbox广泛用于页面布局当中。通过这次实战,让我对Flexbox相关知识有了更进一步的了解,也在这方面增涨了不少的知识。接下来,我将分三个部分来解释Flexbox在Web布局中的实战。
- 主要页面布局(一个JavaScript单页面小应用)
- 流体网格和折叠盒子(Accordion)
- “Cards”和“Slabs”产品
序言
这不是一篇有关于Flexbox的科普教程,这里有些关于Flexbox的其他教程。但简而言之,使用display:flex
可以快速创建一个flexbox或者flex容器。而它的子元素就变成了flex项目,可以设置flex
属性。当然,它们自己也可以变成flex容器。
或许,在使用Flexbox给Web页面进行布局时,还在担心浏览器对其兼容性支持力度。如果你对这方面顾虑较深的话,可以通过caniuse.com来查阅。
如果你希望Flexbox在更多的浏览器上都能有一个较好的渲染或呈现方式,需要添加一些浏览器的私有前缀。可以使用Autoprefixer插件来帮助你处理这些琐碎的事情。
主页面布局
这是一个JavaScript写的单页面应用,页面主要包括了标题栏、页脚、canvas
展示区域和调整窗口大小的列表选择项。如下图所示:
把所有元素都放置在一个.wrapper
容器内,并且通过position:fixed
将其大小设置和视窗大小一样。接下来使用display:flex
将.wrapper
变成flex容器,另外使用flex-direction:column
让flex项目(.wrapper
的子元素)纵向排列。
详细样式用下图向大家展示,将会变得更好理解:
.body-wrapper
设置flex:1
。这样使用的主要目的是将其可以根据容器可用空间自动拉伸填补。简而言之,就是让.body-wrapper
的高度变成(100vh - 标题栏高度 - 页脚高度
)。其实flex:1
是flex: 1 1 0
的简写方式,也就是flex-grow:1
(拉伸)、flex-shrink:1
(缩小)、flex-basis:0
(没有最小高度min-height
)。
.header-wrapper
、.body-wrapper
和.footer-wrapper
是.wrapper
的flex项目,其实它们也是一个flex容器。而且它们的子元素也是一个flex项目,并且是水平方向排列,那是因为flex-direction:row
(也就是flex-direction
的默认值)。另外通过align-items:center
来保证不管是页头或页脚的高度是多少,都让其子元素垂直居中(类似table
中的vertical-align:middle
)。
在.header-wrapper
和.body-wrapper
中都有一个元素设置了flex:1
,主要是让其能自动填充可用空间。而且在.footer-wrapper
中需要给每个flex项目设置flex: 1 1 auto
(改变flex-basis
的值为auto
),这样让.footer-wrapper
的flex项目平分页脚区域宽度。
注意,不管左边的面板.pane-wrapper
设置多少值,.canvas-wrapper
都会自适应。而且如果需要,还可以通过order
属性改变它们的排列顺序。
.pane-wrapper
和.canvas-wrapper
都设置为flex容器,并且能过flex-direction:column
将其flex项目纵向排列(它们都有一个标题区和主体区)。使用flex-direction:row
将.pane-body
设置为flex容器。严格来说在flexbox中是不必要的,因为.canvas-wrapper
和.pane-body
是最终的设置,而且.pane-content
和.canvas
都设置了position:absolute
。它们不会影响外容器的高度计算,它们每个都可以滚动。如果.pane-content
和.canvas
是flex项目的话,看上去不是这样的结果。
在没有Flexbox布局模块之前,我们如何实现类似这样的布局呢?在前一个项目中有一个非常相似的布局,我们给每个区域都使用position:fixed
。这种布局方式对于旧浏览器具有较好的支持。但成本是在CSS要通过像.with-header
、.with-footer
、.with-titlebar
、.with-sidebar
等类名对各个位置进行计算,而且位置改变时还需要通过JavaScript进行动态计算。更为麻烦的是,你改变一个值,其它的容器也要相应的改变。
同时要让行内元素垂直对齐,还需要使用一些让人讨厌的Hacks。
如果你对垂直对齐相关的知识感兴趣,你可以点击这里阅读。
产品列表和摘要盒子
Flexbox很适合流体产品列表(A区)以及像折叠卡片(Accordion)摘要盒子(B区),如下图所示:
在这里面还有一个自适应的弹出窗(Modal),而且能随着窗口的width
和height
缩放按比例调整Modal大小。(使用了Bootstrap的Modal模板,.modal
、.modal-content
和.modal-body
都设置了百分比高度)。首先设置.col-wrapper
为flex容器,并且使用flex-direction:row
让flex项目水平排列。另外设置align-items:stretch
让每一个flex项目具有相同的高(每列等高)。由于它们都在已高度的容器内,使用height: 100%
可以拉伸到全屏高度。.col-content
设置flex:1
,可以让其自动填充水平可用空间,并且通过flex: 0 0 <width>
给.col-facets
和.col-summary
设置宽度百分比。.col-facets
和.col-content
设置了overflow:auto
,因此它们有滚动条。
很多地方对于产品的布局都会采用网格形式,不管是“card”还是“slab”的形式(下一节将详细介绍这部分)。这些都是弹性布局,其宽度都会自适应容器的宽度。但也会使用媒体查询来控制列数,允许在任何屏幕上有一种较好的布局效果。
.product-grid
是一个flex容器。设置了flex-wrap:wrap
允许flex项目可以换行,同时设置align-items:stretch
让同行的flex项目有相同的高度。.product
是flex项目,每个Products有一个1%
的margin-left
和margin-right
。相当于两个flex项目之间有2%
的间距(容器也有一个padding-left
和padding-right
的1%
)。.product
的宽度使用flex-basis
设置一个百分比,其值相当于:flex: 0 0 (100 / 3) - 2%
(三列,每两列之间的间距是2%
)。你也可以看上图中有关于媒体查询部分中相应的调整。
使用Flexbox是制作流体网格最好的方式?这个方法看起来很简单,完全依靠给flex-basis
设置一个百分比值,而不是flex-grow
或者flex-shrink
。似乎没有比float-based
更好的方法,尽管我们具有一样高度的盒子的优势。主要原因是项目最后一行对齐到网格。如果最后一行没有完全填满,大多数flexbox网格会填充空间,允许项目的宽度变长,或者增加它们之间的间距。这些在我们的案例中都是可接受的结果。这里有一个示例,感兴趣的可以看看。
让摘要区域能填满垂直的空间是有一定的挑战性的。.summary-content
拉伸填充可用空间,当空间填满后滚动条也将出现。.summary-box
需要设置height
为100%
(其容器也指定了高度)和.summary-content
需要设置flex-grow: 1
和flex-shrink:1
,让flex项目可以根据需要扩展或缩小。overflow:auto
让容器滚动条在需要的出现。
没有Flexbox,要轻松实现这样的效果是有点不可能,因为无法预知盒子的高度。
Cards和Slabs
产品列表形式要么是大的Cards或者是紧凑形的Slabs。在每种情况下Flexbox都非常有帮助。
.product-card
有一个元素.product-desc
让其自动填充垂直方向的可用空间。如果指定一个max-height
,.product-desc
会被截断。如果我们想把图片放到标题上面,在Flexbox布局上除了改变HTML结构之外,还可以通过order
来改变他们的顺序。
对于.product-slab
我们需要内容两端对齐,在没有Flexbox,需要采用float
和清除浮动,但无法根据内容数量分配水平空间,这对于前端来说是一种痛苦。那么有了Flexbox,这一切变得都轻松。
flex-direction:row
让内容水平排列。通过justify-content:space-between
让标题和内容实现两端对齐。在.product-title
设置flex-grow:1
确保水平空间内能让其居左对齐。
总结
这个项目是一个宝贵的学习经验。Flexbox可能让你得到出人意料的结果,大家应该以最好的方式和认真的学习它。尽管大多数项目中还不能依靠Flexbox来做布局,主要是考虑浏览器的兼容性。但仍然有很多例子证明了,可以对Flexbox做一些降级处理。比如@Zoe Gillenwater整得的相关教程和资料。时到今日,使用Flexbox的场景也越来越多,在将来使用Flexbox场景将会更多。
为了让这篇文章篇幅不至于过长,我试图尽可能保持简洁,如果文章中有解释不清楚的或者有些事情不对的,希望帮忙指出。如果想对Flexbox做深入的学习和研究,建议点击这里了解更多的相关内容。
本文根据@Francois Jordaan的《Going all-in on Flexbox》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://www.isotoma.com/blog/2016/09/07/going-all-in-on-flexbox/。
如需转载,烦请注明出处:http://www.w3cplus.com/css3/going-all-in-on-flexbox.html