从一个需求案例说起
▐ 背景
商品卡片,是电商的经典场景。一个典型的商品卡片大概长这个样子:


商品卡片里通常有商品图、名称、价格、券、销量、行动按钮、利益点。除了这些,不同业务侧还会设计一些特殊表达。由于信息众多,布局上也往往比较复杂。
▐ 传统布局
传统实现上,使用 flex 端方案时,可以这么做。根据各信息的横纵排布,将其分割成多个容器盒子:

你的 html 可能是这样的:
<div className="card">
<div className="card-top">
<div className="card-top-left">商品图</div>
<div className="card-top-right">
<div className="card-top-right-top">热销指数</div>
<div className="card-top-right-bottom">商品信息</div>
</div>
</div>
<div className="card-bottom">
<div className="card-bottom-left">商品价格</div>
<div className="card-bottom-right">行动按钮</div>
</div>
</div>
你的 css 大概长这样:
.card {
display: flex;
flex-direction: column;
.card-top {
flex: 1; /* 容器自适应*/
display: flex;
.car-top-left {
width: 250rpx;
}
.car-top-right {
flex: 1;
display: flex;
flex-direction: column;
.car-top-right-top {
height: 50rpx;
}
.car-top-right-bottom {
flex: 1;
display: flex;
flex-direction: column;
}
}
}
.card-bottom {
/* 给一个固定高度 */
height: 50rpx;
display: flex;
justify-content: space-between;
.car-bottom-left {
/* 自适应容器 */
flex: 1;
}
.car-bottom-right {
width: 50rpx;
}
}
}
如上所示,为了让各个信息模块变成响应式,你不得不写很多容器元素,实际内容处在嵌套元素的最深处。
为了自证没有夸张,有兴趣的同学可以去检查一下这个榜单商品卡的元素,你会发现卡片布局结构长这样:
这个现象的核心在于,flex 的布局方案是一维的。为了实现二维的卡片布局,你不得不按照信息排布将二维拆成多个一维容器来处理。
那么有没有更好的布局方案呢?
▐ 网格布局
<div className="card">
<div className="img">商品图</div>
<div className="guide">热销指数</div>
<div className="info">商品信息</div>
<div className="price">商品价格</div>
<div className="action">行动按钮</div>
</div>
css 是这样的:
.card {
/**
* 容器元素设为 gird 类型,定义三行两列,使用指定距离或弹性距离
*/
display: grid;
grid-template-columns: 262rpx 1fr;
grid-template-rows: 50rpx 212rpx 1fr;
/* 申明每个内容元素占据的网格范围 */
.img {
grid-row-start: 1;
grid-row-end: 3;
}
.guide {
grid-column-start: 2;
}
.info {
grid-row-start: 2;
grid-column-start: 2;
}
.price {
grid-column-start: 1;
grid-row-start: 3;
}
.action {
grid-column-start: 2;
grid-row-start: 3;
}
}
从 html 结构来看非常纯粹,除了最外层的容器元素,全是内容元素。卡片结构长这样:
这里涉及到 grid 的几个常用属性,简单说明一下:
父元素:
子元素:
grid-template-columns
:定义容器的列数和各列的宽度
grid-template-rows
:定义容器的行数和各行的高度
grid-column-start
:子元素所在区域的起始列号
grid-row-start
:子元素所在区域的起始行号
就这个例子而言,这里其实只需要定义好图片的网格范围,其它元素按顺序排列下来也是刚好符合我们预期的,css 代码也可以更简洁:
.card {
/**
* 容器元素设为 gird 类型,定义三行两列,使用指定距离或弹性距离
*/
display: grid;
grid-template-columns: 262rpx 1fr;
grid-template-rows: 50rpx 212rpx 1fr;
/* 只为特殊范围的元素定义网格范围 */
.img {
grid-row: 1 / 3;
}
}
grid-row
是
grid-row-start
/
grid-row-end
的简写。
GRID 入门
见证了 grid 的强大,现在可以重新认识一下 grid 布局了。
根据 mdn 的说法:网格是由一系列水平及垂直的线构成的一种布局模式。根据网格,我们能够将设计元素进行排列,帮助我们设计一系列具有固定位置以及宽度的元素的页面,使我们的网站页面更加统一。
▐ 现代布局技术--mdn
mdn地址:https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Grids#flexible_grids_with_the_fr_unit
网格布局教程地址:https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Grids#flexible_grids_with_the_fr_unit
但我更建议你花半个小时看一下这篇 CSS 布局介绍,它从布局流理论开始讲起,一路介绍了早期前辈们的各种布局 hack 手段(在没有 flex 和 grid 之前,如何使用表格和浮动属性完成各种复杂布局,甚至也实现了一定的响应式),直到 flex 横空出世,各种布局手段、媒体查询纷至沓来。
CSS布局介绍地址:https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Introduction
▐ 阮一峰 CSS 网络布局教程
CSS 网络布局教程地址:https://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html

▐ GRID GARDEN
GRID GARDEN地址:https://cssgridgarden.com/

▐ An Interactive Guide to CSS Grid
An Interactive Guide to CSS Grid 地址:https://www.joshwcomeau.com/css/interactive-guide-to-grid/

▐ 可视化生成布局代码
可视化生成布局代码 地址:https://cssgrid-generator.netlify.app/
可视化调整网格布局,生成布局 css 和 html 代码:


通过网格布局,我们可以轻松实现这些效果:
▐ 羽毛球场地

▐ 房间平面图
https://codepen.io/anonbug/pen/OJqbrQL
除了 cad,我们也有了前端侧的平面图表达。
▐ 蒙德里安画
https://codepen.io/anonbug/pen/gOEmwoQ
没错,只需要几行代码,你就能快速复现蒙德里安经典名画:

▐ 日历
日历也是另一个 grid 布局所擅长的领域,我很难想象 flex 布局要怎么适应不确定的尾部元素对齐(其实可以做到啦,只是夸张一下…

▐ 垂直居中
div {
display: flex;
justify-content: center;
align-items: center;
}
现在
div {
display: grid;
place-items: center;
}

本文分享自微信公众号 - 大淘宝技术(AlibabaMTT)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。