经典flex布局示例
导航
场景
场景特点: 一维布局、内容决定box大小
布局分析
核心实现
.container {
display: flex;
gap: 8px;
}
.right {
margin-left: auto;
}
完整代码见附录1
绝对底部
场景
场景特点:一维布局(纵向)、绝对底部
布局分析
由图可见,使用绝对底部时,无论title、jpg、description部分如何调整都不会影响整体布局。
核心实现
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.container > div {
flex: 1 1 auto;
}
完整代码见附录2
经典grid场景示例
由上图可知,grid在复杂组件布局(比如页面框架)上具有优势。
grid二维优势对比示例
场景
场景特点: 二维布局,垂直对齐、水平靠左对齐;box大小等比,需要考虑1920px和1280px场景
布局分析
核心实现
gird布局实现
display: grid;
gap: 8px;
// fr单位表示可用空间的一份,所有box按比例分配可用空间
grid-template-columns: repeat(3, 1fr);
完整代码见附录3
flex布局实现
.container {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.container > * {
// 允许在150px的基准上伸缩,150px表明一行只允许放置3个box
flex: 1 1 150px;
}
// 设置一个相同大小的伪元素作为最后一个box
.container::after {
content: '';
flex: 1 1 150px;
}
完整代码见附录4
对比
grid在实现二维布局上更灵活,flex在实现如上布局时略显吃力。如果一列box数从3改为4,grid只需将repeat中3改为4,而flex需要较大调整。
注意:当允许弹性box换行时,每个新行都变成了一个新的弹性容器。空间分布1只在行内进行。
思考
问题:grid布局是flex布局的扩展还是替代?
问题详情: 除了少数内容决定盒子大小的场景,grid在布局决定盒子大小的场景是不是可以覆盖到并替代flex?
os:我们知道一维布局下,我们一般推荐使用flex,但布局决定盒子大小的一维布局场景下,使用flex比grid更具优势吗?
场景&布局
场景特点: 一维布局、box等比展示
核心实现对比
/* 方式一:flex布局 */
.container {
display: flex;
gap: 8px;
}
.container > * {
flex-grow: 1
}
/* 方式二:grid布局 */
.container {
display: grid;
gap: 8px;
grid-template-columns: repeat(3, 1fr);
}
完整代码见附录5
对比可知,flex布局对box数不指定,对任意box数实现动态布局;而grid布局需要指定行数,即box数为指定值。所以flex更支持一维场景下的动态配置。若box数为指定值,那可能使用grid和flex差别不大(作者暂未发现差别。不考虑底层实现差别,比如渲染方式等)。
其他对比
浏览器兼容性(chrome为例)
display:flex需要浏览器版本>=21,浏览器对flex属性支持较早,相对稳定;display:grid需要浏览器版本>=57,感觉支持程度也可以。
开发者熟悉程度
简单调研发现大部分前端开发者对flex比grid更熟悉一些。
小结
在一维布局的动态分配场景下,flex更灵活;动态指的是,比如box数不固定、内容决定box大小等。而在二维空间、布局决定盒子大小时,grid更具优势。2
在开发习惯上,一维场景下我们推荐使用flex布局,即便有些场景grid也可以实现;在二维场景下,我们推荐使用grid布局。
相关资料
附录
附录1
// html
<div class="container">
<div>menu1</div>
<div>menu2</div>
<div>long menu3</div>
<div class="right">icon1</div>
<div>icon2</div>
</div>
// css
.container {
display: flex;
gap: 8px;
}
.right {
margin-left: auto;
}
.container {
width: 500px;
border: 2px dotted rgb(96, 139, 168);
}
.container > * {
padding: 0 8px;
border: 2px solid rgb(96, 139, 168);
border-radius: 5px;
background-color: rgba(96, 139, 168, 0.2);
}
附录2
// html
<div>
<div class="container">
<div class="title">标题:配置logo</div>
<div>
<img src="//www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" width="200px">
</div>
<div>描述: 这是这个logo的详细描述,描述很长,可能占用很多行</div>
<button>更新logo</button>
</div>
</div>
// css
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.container > div {
flex: 1 1 auto;
}
.title {
align-self: start;
font-weight: bold;
font-size: 18px;
}
.container {
width: 200px;
height: 300px;
padding: 8px;
border: 2px dotted rgb(96, 139, 168);
}
button {
width: 80px;
border: 2px solid rgb(96, 139, 168);
border-radius: 5px;
background-color: rgba(96, 139, 168, 0.2);
}
附录3
// html
<div class="container">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
// css
.container {
display: grid;
gap: 8px;
grid-template-columns: repeat(3, 1fr);
}
.container {
width: 500px;
border: 2px dotted rgb(96, 139, 168);
}
.container > * {
height: 50px;
border: 2px solid rgb(96, 139, 168);
border-radius: 5px;
background-color: rgba(96, 139, 168, 0.2);
}
附录4
// html
<div class="container">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
// css
.container {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.container > * {
flex: 1 1 150px;
}
.container::after {
content: '';
flex: 1 1 150px;
}
.container {
width: 500px;
border: 2px dotted rgb(96, 139, 168);
}
.container > * {
height: 50px;
border: 2px solid rgb(96, 139, 168);
border-radius: 5px;
background-color: rgba(96, 139, 168, 0.2);
}
附录5
// html
<div class="container">
<div>One</div>
<div>Two</div>
<div>Three <br />has <br />extra <br />text</div>
</div>
// css
/* 方式一:flex布局 */
.container {
display: flex;
gap: 8px;
}
.container > * {
flex-grow: 1
}
/* 方式二:grid布局*/
/* .container {
display: grid;
gap: 8px;
grid-template-columns: repeat(3, 1fr);
} */
.container {
width: 500px;
border: 2px dotted rgb(96, 139, 168);
}
.container > * {
border: 2px solid rgb(96, 139, 168);
border-radius: 5px;
background-color: rgba(96, 139, 168, 0.2);
}