精读《用 css grid 重新思考布局》

1 引言

Flex 与 Grid 相比就像功能键盘和触摸屏。触摸屏的控制力相比功能键盘来说就像是降维打击,因为功能键盘只能上下左右控制(x、y 轴),而触摸屏打破了布局障碍,直接从(z 轴)触达,这样 无论 UI 内部布局再复杂,都可以通过 touch 直接定位。

Flex 是一维布局方式,我们需要不断嵌套 Div 才能形成复杂结构,而一旦布局产生了变化,原有嵌套结构如果不能 “兼容变化” 到新结构,代码就需要重构。而 Grid 就像触摸屏一样,可以二维布局,即便布局方式做了翻天覆地的调整,也仅需少量修改就能适配。

这就是这次精读 用 css grid 重新思考布局 的原因,理解这个革命性布局技术给布局,甚至代码逻辑组织带来的变化。

2 概述

作者首先抛出了 Flex 的问题,其实是 block float flex 这三种布局模式的通病:

  • 布局结构由 Div 层级结构描述,导致 Div 层级复杂且遇到结构变更时难以维护。
  • 定制能力弱。Flex 布局有一些不受控制的智能设定,比如宽度 50% 的子元素会被同级元素挤到 50% 以下,这种智能化在某些场景是需要的,但由于没有提供像 Grid 的 minmax 之类的 API,所以定制型不足。

举个例子,上图的结构用 Flex 描述可能是这样的:

<div class="card"><div class="profile-sidebar"><img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img" /><ul class="social-list"><li><a href="#" class="social-link"><i class="fab fa-dribbble-square"></i></a></li><li><a href="#" class="social-link"><i class="fab fa-facebook-square"></i></a></li><li><a href="#" class="social-link"><i class="fab fa-twitter-square"></i></a></li></ul></div><div class="profile-body"><h2 class="profile-name">Ramsey Harper</h2><p class="profile-position">Graphic Designer</p><p class="profile-info">Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere a tempore,dignissimos odit accusantium repellat quidem, sit molestias dolorumplaceat quas debitis ipsum esse rerum?</p></div>
</div>

利用 HTML 嵌套结构,我们将图形纵向分成两大块,然后在每块内部继续嵌套划分布局,这是最经典的布局行为了。

样式文件里,我们需要对每层布局进行描述,同时支持多分辨率弹性布局,包括顶层 card 容器在内的一些样式需要做一定调整:

.card {width: 80%;margin: 0 auto;display: flex;flex-direction: column;max-width: 600px;background: #005e9b;flex-basis: 250px;color: white;padding: 2em;text-align: center;
}.profile-info {font-weight: 300;opacity: 0.7;
}.profile-sidebar {margin-right: 2em;text-align: center;
}.profile-name {letter-spacing: 1px;font-size: 2rem;margin: 0.75em 0 0;line-height: 1;
}.profile-name::after {content: "";display: block;width: 2em;height: 1px;background: #5bcbf0;margin: 0.5em auto 0.65em;opacity: 0.25;
}.profile-position {text-transform: uppercase;font-size: 0.875rem;letter-spacing: 3px;margin: 0 0 2em;line-height: 1;color: #5bcbf0;
}.profile-img {max-width: 100%;border-radius: 50%;border: 2px solid white;
}.social-list {list-style: none;justify-content: space-evenly;display: flex;min-width: 125px;max-width: 175px;margin: 0 auto;padding: 0;
}.social-link {color: #5bcbf0;opacity: 0.5;
}.social-link:hover,
.social-link:focus {opacity: 1;
}.bio {padding: 2em;display: flex;flex-direction: column;justify-content: center;
}@media (min-width: 450px) {.bio {text-align: left;max-width: 350px;}
}.bio-title {color: #0090d1;font-size: 1.25rem;letter-spacing: 1px;text-transform: uppercase;line-height: 1;margin: 0;
}.bio-body {color: #555;
}.profile {display: flex;align-items: flex-start;
}@media (min-width: 450px) {.card {flex-direction: row;text-align: left;}.profile-name::after {margin-left: 0;}
}

让我们看看 Grid 是怎么做的吧!Grid 有许多 API,我们重点看 grid-template-areas 这个属性,利用它,我们可以不关心模块的 HTML 结构,直接平铺方式描述:

<div class="card"><img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img" /><ul class="social-list"><li><a href="#" class="social-link"><i class="fab fa-dribbble-square"></i></a></li><li><a href="#" class="social-link"><i class="fab fa-facebook-square"></i></a></li><li><a href="#" class="social-link"><i class="fab fa-twitter-square"></i></a></li></ul><h2 class="profile-name">Ramsey Harper</h2><p class="profile-position">Graphic Designer</p><p class="profile-info">Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere a tempore,dignissimos odit accusantium repellat quidem, sit molestias dolorum placeatquas debitis ipsum esse rerum?</p>
</div>

可以看到,使用 Grid 可以将 UI 结构与 HTML 结构分离,HTML 结构仅描述包含关系,我们只需在样式文件中描述具体 UI 结构。

样式文件只截取 Grid 相关部分:

.card {width: 80%;margin: 0 auto;display: flex;flex-direction: column;max-width: 600px;background: #005e9b;flex-basis: 250px;color: white;padding: 2em;text-align: left;display: grid;grid-template-columns: 1fr 3fr;grid-column-gap: 2em;grid-template-areas:"image name""image position""social description";
}.profile-name {grid-area: name;
}
.profile-position {grid-area: position;
}
.profile-info {grid-area: description;
}
.profile-img {grid-area: image;
}
.social-list {grid-area: social;
}

可以看到,grid-template-areas 是进一步抽象的语法,将页面结构通过直观的文本描述,无论是理解还是修改都更为轻松。

这种描述方式适配不同分辨率下也具有优势,只要重组 grid-template-areas 即可:

@media (min-width: 600px) {.card {text-align: left;grid-template-columns: 1fr 3fr;grid-template-areas:"image name""image position""social description";}
}

归根结底,Grid 通过二维结构描述,将子元素布局控制收到了父级,使布局描述更加直观。

最后作者也提到,Flex 依然有使用场景,即简单的一维结构,或者 space-between 等 Flex 独有语法的情况。因此推荐整体、复杂的二维布局采用 Grid,一维的简单布局采用 Flex。

3 精读

Grid 的布局思路给了我很多启发,HTML 结构与 UI 结构的分离有助于减少 DIV 的层级结构,使代码看上去更清晰。

也许有人会疑惑,Grid 无非将 HTML 布局部分功能挪到了 CSS,整体复杂度应该不变。其实,从 grid-template-areas 这个 API 可以看到,Grid 不仅仅将布局功能抽到 CSS 中,更是将布局描述进行了一层抽象,使代码更易维护。

抽象,再抽象

为什么 Grid 可以对布局进行抽象?因为 Grid 将二维结构都掌握在手中,得到了更大的布局能力,才能进一步将结构化语法抽象为字符串的描述。

抽象的好处是不言而喻的,你觉得一堆嵌套的 DIV 与下面的代码,哪个更易读呢?

.card {grid-template-areas:"image name""image position""social description";
}

这就是抽象的好处,一般来说,代码抽象程度越高就越易读,越易维护。

再看一个 Chrome Grid 插件,将 Grid 可视化显示出来,并可以以 UI 方式进行调整:

UI 是对文本的再抽象,同时可以规避一些不可能存在的语法,比如:

.card {grid-template-areas:"image name""image position""social image";
}

布局只能以凸多边形方式拓展,不可能分离,也不可能突然插入一个其他模块而变成凹多边形。因此 UI 可以将这个错误规避,并简化为横竖多条线的方式对 UI 进行划分,显然这种描述方式效率更高。

不得不说,Grid 以及图形化插件的探索,是布局领域的一大进步,是不断抽象的尝试,要解决的问题只有一个:如何提供一种更直观的描述 UI 的方式。

布局对模块化的影响

Grid 将布局方式提高了一个维度,会直接影响到 JS 模块化方式。

尤其是以 JSX 组织代码的情况下,一个模块等于 UI + JS,通过嵌套方式的布局会让我们更倾向于站在 UI 视角划分模块。

比如对于上图模块,如果用 Flex 方式布局,我们可能会首先创建模块 X 作为左侧容器,子元素是 A 和 B,创建模块 Y 作为右侧容器,子元素是 C 以及新容器 Z,Z 容器的子元素是 D 和 E。

如果你的第一印象是这么组织代码,不得不承认模块化会受到布局方式的影响。虽然许多时候这样划分是正确的,但当这 5 个模块各自没有关联时,我们创建的容器 X、Y、Z 就失去了复用性,在新的组合场景我们又要重新组合一遍。

但是在 Grid 语法中,我们不需要 X、Y、Z,只需要用 css grid generator 按照上图的方式拖拖拽拽即可自动生成如下布局代码:

.parent {display: grid;grid-template-columns: 3fr repeat(2, 1fr);grid-template-rows: repeat(5, 1fr);grid-column-gap: 0px;grid-row-gap: 0px;
}.div1 {grid-area: 1 / 1 / 3 / 2;
}
.div2 {grid-area: 3 / 1 / 6 / 2;
}
.div3 {grid-area: 1 / 2 / 2 / 4;
}
.div4 {grid-area: 2 / 2 / 6 / 3;
}
.div5 {grid-area: 2 / 3 / 6 / 4;
}

其实 grid-template-columns grid-template-rows 组合起来使用比 grid-template-areas 更强大,但是纯代码方式描述没有 grid-template-areas 直观,可是配合一些可视化系统就非常直观了:

将 A ~ E 这 5 个模块布局抽出来后,它们之间的关系就打平了,我们可以完全从逻辑视角审视如何做模块化了。

4 总结

CSS Grid 本质上是一种二维布局的语法,相比 Block、Flex 等一维布局方案,多了一个维度可以同时从行与列角度定义布局,因此派生出 grid-template-areas 等语法,整体上更内聚更直观,抽象度也更高了。

理解了这些也就理解了布局未来的发展方向,让布局与 Dom 分离 一直是前端的一个梦想,开发 UI 部分时,只需关心页面由哪些模块组成,去实现这些模块就行了,而不需要关心模块之间应该如何组合。在描述组合时,可以通过可视化或比较抽象的字符串描述布局的结构,并对应到写好的模块上,这样的代码维护性远高于用 DIV 描述结构的方案。

讨论地址是:精读《用 css grid 重新思考布局》 · Issue #211 · dt-fe/weekly

如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/509840.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue使用高德地图定位到当前位置,并显示天气信息

首先得去高德控制台申请两个 key&#xff0c;一个天气key和一个定位key 获取天气信息的函数&#xff1a; const getWeather function (city) {// 使用 fetch 发送请求获取天气信息fetch(https://restapi.amap.com/v3/weather/weatherInfo?city${city}&keyeefd36557b0250…

云计算——ACA学习 弹性伸缩概述

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 写在前面 本系列将会持续更新云计算阿里云ACA的学习…

VuePress + GitHub 搭建个人博客踩坑记录

最近想给我教练搭个网站,本来选的是 VuePress 框架,也折腾完了,起码是搭建出来了,踩的坑也都总结好了 但是最近发现了一个更简洁的模板: VuePress-theme-hope ,所以最终网站使用的样式是这个 不过我觉得这里面踩坑的记录应该还是有些价值的,分享出来,看看能不能帮到一些小伙伴~…

一线大厂软件测试面试题及答案解析,2024最强版...

【软件测试面试突击班】2024吃透软件测试面试最全八股文攻略教程&#xff0c;一周学完让你面试通过率提高90%&#xff01;&#xff08;自动化测试&#xff09; 1、什么是兼容性测试?兼容性测试侧重哪些方面? 参考答案: 兼容测试主要是检查软件在不同的硬件平台、软件平台上…

无人机遥感在农林信息提取中的实现方法与GIS融合应用

在新一轮互联网信息技术大发展的现今&#xff0c;无人机、大数据、人工智能、物联网等新兴技术在各行各业都处于大爆发的前夜。为了将人工智能方法引入农业生产领域。首先在种植、养护等生产作业环节&#xff0c;逐步摆脱人力依赖&#xff1b;在施肥灌溉环节构建智慧节能系统&a…

Vue.js+SpringBoot开发高校实验室管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

15 easy 141. 环形链表

法1&#xff1a;快慢指针法&#xff1a; //给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 // // 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数…

深度相机xyz点云文件三维坐标和jpg图像文件二维坐标的相互变换函数

深度相机同时拍摄xyz点云文件和jpg图像文件。xyz文件里面包含三维坐标[x,y,z]和jpg图像文件包含二维坐标[x&#xff0c;y],但是不能直接进行变换&#xff0c;需要一定的步骤来推演。 下面函数是通过box二维框[xmin, ymin, xmax, ymax, _, _ ]去截取xyz文件中对应box里面的点云…

使用OpenTelemetry进行监控

工具介绍 注意&#xff1a;该部分介绍摘抄自&#xff1a;搭建高级的性能监控系统(PrometheusGrafanaNode ExporterAlertmanager) - 爱云 Prometheus、Grafana、Node Exporter 和Alertmanager是一组用于监控和可视化系统性能的开源工具。它们通常一起使用&#xff0c;形成一个强…

课题学习(二十)----阅读《近钻头井斜动态测量重力加速度信号提取方法研究》论文

摘要&#xff1a;利用加速度计进行近钻头井斜动态测量时&#xff0c; 钻具的高速旋转、 井下强振动、强冲击环境给重力加速度测量带来极大干扰&#xff0c;如何从干扰噪声中有效提取重力加速度信号对于提高井斜角和工具面角的测量精度至关重要。 根据重力加速度径向和切向分量为…

视频云平台——搭建SRS5平台支持GB28181视频流的推送

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不仅…

网络编程作业day3

项目作业1&#xff1a;TCP机械臂测试 客户端操作代码&#xff1a; /*机械臂客户端控制代码*/ #include <myhead.h>#define SER_IP "192.168.125.176" //机械臂服务器IP地址 #define SER_PORT 8888 //机械臂服务器端口号 #define CLI_IP "…