博客列表 >深刻理解Flex与Grid布局和Grid实现栅格化封装

深刻理解Flex与Grid布局和Grid实现栅格化封装

吾逍遥
吾逍遥原创
2020年10月30日 20:00:282851浏览

一、开始之前想说的

本文是我对Flex和Grid布局理解的全面总结,所以文章有点长,希望有耐心看下去,我相信你会有所收获。还有是最好有Flex布局和Grid布局属性的了解,不然看起来可能有点吃力。这里可以看下我的博文

《BFC和flex布局探讨和演示》https://www.php.cn/blog/detail/24616.html
《Flex项目属性和PC端响应式页面》 https://www.php.cn/blog/detail/24648.html
《Grid布局基本概念和隐式排列》 https://www.php.cn/blog/detail/24657.html

其实最后一篇可以看下隐式排列,前面内容我在本文中进行更便于理解的总结。

昨晚朱老师已经讲完了Grid布局和一些实战案例,可以说CSS布局告以段了。说实在话报班前,我最愁的就是布局,虽然以前看过阮一峰老师的Flex布局和Grid布局教程,也会简单使用,但不能算上理解,主要是老师没讲Flex和Grid关联和区别,一般都是一句,前者是一维,后者是二维。直到老师讲完grid全部属性后,晚上回想时豁然开朗,原来Flex布局优势在一维,而Grid布局优势在二维 ,为什么这样说,后面会有具体分析。再者面对Grid诸多属性,什么时候使用那个相信一般都会比较迷茫,我对Grid布局进行了整体解说,相信你也会和我一样对它了如指掌。

二、换种方式来理解和掌握Grid布局的容器属性和项目属性

这里我不按平常的顺序来探讨grid容器属性和项目属性,因为我觉得它们非常不便于记忆和理解。这里我将Grid布局分为两大部分: “画和调整”网格单元调整网格单元与网格项目对齐方式。其实grid布局借鉴了excel表格的建表思维Flex布局的方向与对齐方式,再加上table的间隙理念而来。

  • Excel的建表思维: 就是说grid布局首先要画出网格,然后调整网格,最后调整网格单元和网格项目进行对齐方式,你可以仔细想想,无论是显示网格单元还是隐式网格单元,它是不是我们日常操作Excel表格的建表思维。
  • Flex的方向和对齐方式: 毕竟是网络,对齐方式不可能再和Excel一样,而Flex对齐方式是比较优秀解决方案,不过Grid将它扩展到二维。
  • table的间隙: Excel表格没间隙一说,而网页需要间隙,难道要和Flex一样使用外边距,明显比较low,它采用了table的间隙。

如果你理解了我上面说的,你也就理解了为什么老师经常说grid是集大成者,目前巅峰布局技术,一切布局在它面前都是毛毛雨。

1、画和调整网格单元

网格单元分为单元格网格区域两种,那么在第一部分是如何体现呢?我认为在grid建立之初使用容器属性grid-template-columns和grid-template-row画的网格单元就是单元格 ,再使用项目属性grid-column、grid-row和grid-area调整网格单元后,此时网格单元应该称为网格区域,即使它是一个单元格。

(1)画出单元格式的网格单元

涉及属性: 容器属性grid-template-columns列宽和grid-template-rows行高
主要作用: 画出网格是几行几列,此时网格单元就是单元格
取值:

  • 绝对值和相对值 就是px、em、vw、vh、vmax和vmin等。此时网格项目设置的width和height无效。
  • 百分比: 它是依据网格容器的width和height,若未 显示指明 (即未使用width和height,内容撑开宽度和高度不算)时,列宽向上寻找,若都没有指明,则是视图区的宽度;而行高只要网格容器没有显示指明高度 ,则为0,此时行高是该行所有项目高度最大值(若设置项目高度,则忽略内容撑开的高度)。
  • 关键字auto: 列宽分配最大剩余空间,而行高在网格容器显示指明高度时同列宽一样分配最大剩余空间 ,若未指明高度则是0,此时行高计算同百分比。
  • fr: MDN解释是弹性系数,可以理解为它是占剩余空间的比例。就是将剩余空间分成N等份,各网格项目根据1fr占1份,2fr占2份…分配剩余空间。非常类似Flex的放大因子flex-grow和缩小因子flex-shrink。
  • minmax(min,value):value大于min时它等于value ,若value < min时它等于min ,它是取二者取大值。要注意min不能取fr
  • 不常用关键字: 如max-content、min-content和fit-content(),在测试发现三者没多大区别,也比较晦涩难以懂,也许max-content有用点,就是列宽或行高由内容来决定

重复: 在设置列宽和行高时经常有大量重复的值,此时可以使用repeat来指定重复。

  • repeat格式: 第一个参数重复次数,第二个参数可以是长度或fr
  • 常规使用: 如repeat(3,10em)、repeat(3,10%)等
  • 重复关键字auto-fit: 这个参数有时非常有用,它表示一行最大的分配网格单元,分配不完则换行,这个概念就非常像flex布局。grid-template-coloumn:repeat(auto-fit,max-content)就相当于flex-flow:row wrap了。
  1. grid-template-columns: 100px 10em 10% auto;
  2. grid-template-rows: 20px 10% auto 5em;
  3. grid-template-columns: 1fr 2fr minmax(2em, 1fr) minmax(20px, 20%);
  4. grid-template-rows:repeat(3,5em);
  5. grid-template-columns:repeat(auto-fit,10em);
  6. grid-template-columns:max-content min-content fit-content(50px);

grid-unit0

(2)合并单元格成网格区域式的网格单元

正如Excel建表一样,上面只是已经将网格分成几行几列,下面就要根据项目(内容)大小来要合并单元格,组成网格区域放它们。

涉及属性: 项目属性grid-column、grid-row和grid-area。
主要作用: 合并单元格为网格区域,此时网格单元就是网格区域
格式:

  • 网格区域列合并grid-column:列起始线 / 列结束线
  • 网格区域行合并grid-row:行起始线 / 行结束线
  • 网格区域grid-area:行起始线 / 列起始线 / 行结束线 / 列结束线

常见形式:

  • 网格线号: 如grid-column: 1 / 3第一列到第三列,grid-area:1 / 1 / 2 / 3 第一行到第二行,第一列到第三列
  • 跨行或列关键字span: 如grid-row: 1 / span 3;表示行起始线为1,跨3行,其它类似。
  • span时忽略起始值: 若是从目前自身位置开始行或列,使用span时则可以忽略不写起始线值 。如grid-column:span 3;或grid-area:span 2 /span 3;
  • 只有一个span: 只有一个span时,要注意它仅表示跨行,不跨列。
  • -1特殊值: 在grid的网格线号系统中,有起始线开始的1、2…,也有从结束线向起始线的-1、-2…。grid中-1表示最后一列或行的网格线号,grid-column: 2 / -1;就是表示从网格列2号线跨列到最后。
  1. .container .item:nth-child(7) {
  2. background-color: yellow;
  3. /* grid-column: 3 / 5; */
  4. /* grid-row: 1 / span 2; */
  5. grid-row: span 2;
  6. /* grid-area: 1 / 3 / span 2 / span 2; */
  7. /* grid-area:span 2 / span 2; */
  8. /* grid-area: span 2; */
  9. }

grid-unit1

(3)补充说明两点

隐式网格单元: 也类似Excel表格外灰色区域,使用容器属性grid-auto-columns和grid-auto-rows设置列宽和行高,它们取值可参考grid-template-columns和grid-template-rows。

区域模板调整网格单元: 容器属性grid-template-area可在容器就调整表格,但它依据项目属性grid-area,所以它仍然可看成项目属性调整,因为要设置网格区域名称再调整,比较赞同老师的说法,有点鸡肋。了解可以百度下,我不推荐这种做法。

2、调整网格单元与网格项目对齐方式

上面已经把网格画好,也调整成网格区域式的风格单元,放入网格项目了,此时我们就可以调整它们对齐方式了,但要分成两部分调整:即网格单元在网格容器中对齐方式网格项目在网格单元中对齐方式 。经我测试,老师说的网格项目在网络容器中对齐方式并不合适,因为网格项目是在网格单元中,尤其是网格项目不占满网格单元时更明显。对齐方式是参考了Flex布局中对齐方式,在我的博文中有分析,常见分为两种处理方式所有项目为一个整体每个项目为个体 。这里也是这样,而且比flex更好记,都是place为前缀的属性,place-content、place-items和place-self,最后一个一看就是自己的,如flex中align-self。对齐方式与flex不同就是拓展到二维。每个属性由两个值构成。

(1)网格单元在网格容器中对齐方式

涉及属性: 容器属性place-content。
主要作用: 网格单元在网格容器中对齐方式 。
格式: 垂直方向align-content 水平方向justify-content
两种处理方式:

  • 所有网格单元为一个整体 : 可取值有start(默认值)、center、end和stretch。如place-content:start center;垂直方向贴起始线,水平方向居中。
  • 网格单元作为个体 :可取值space-between,space-around,space-evenly,含义和flex对齐方式中一样,有疑问可看那篇博文。

若是垂直方向和水平方向值一样,可简写成一个值,如place-content:center。

  1. .container{
  2. /* place-content: start; */
  3. /* place-content:center; */
  4. /* place-content:end; */
  5. /* place-content: space-between; */
  6. place-content: space-around;
  7. /* place-content: space-evenly; */
  8. }

grid-align0

grid-align1

(2)所有网格项目在各自网格单元中对齐方式

涉及属性: 容器属性place-items。
主要作用: 网格单元在网格容器中对齐方式 。
格式: 垂直方向align-items 水平方向justify-items
取值: 就四个值;start、center、end和stretch。若二者相等可只写一个来表示。

  1. .container {
  2. place-items: center;
  3. }

grid-align2

(3)某个网格项目在网格单元中对齐方式

涉及属性: 项目属性place-self。
主要作用: 网格单元在网格容器中对齐方式 。
格式: 垂直方向align-self 水平方向justify-self
取值: 就四个值;start、center、end和stretch。若二者相等可只写一个来表示。

  1. .container .item:nth-child(5){
  2. background-color: yellow;
  3. place-self:end center;
  4. }

grid-align3

3、网格单元的排列方向和间隙

上面基本完成了网格的大部分了,正如Flex布局有换行方向flex-flow,grid对应有排列方向容器属性grid-flow,网格单元的间隙,在Flex布局中一般是通过margin来实现,便table的间隙方案比较优秀,grid的间隙采用它的方式,对应的属性为容器属性gap。比较简单,取值可百度下。

上面就是换种方式理解掌握grid的容器属性和项目属性,不知你掌握没。下面是老师发的各属性表格。

术语

序号 术语 描述
1 网格容器 dispaly:grid属性定义的元素
2 网格项目 网格容器的直接子元素
3 网格单元 放置网格项目的空间,有单元格网格区域二种类型
4 单元格 放置网格项目的最小单元
5 网格区域 由一个或多个单元格组成的矩形区域

常用属性

序号 属性 描述
1 grid-template-columns 定义网格轨道中的列宽
2 grid-template-rows 定义网格轨道中的行高
3 gap 网格轨道间距
4 grid-auto-flow 项目在容器中的排列方向
5 grid-auto-rows 隐式网格单元的行高
6 grid-auto-columns 隐式网格单元的列宽
7 grid-row-start 行起始线
8 grid-row-end 行结束线
9 grid-column-start 列起始线
10 grid-column-end 列结束线
11 grid-row 定义行起始与结束线
12 grid-column 定义列起始与线束线
13 grid-area 定义网格区域
14 place-items 所有项目在网络单元中的对齐方式
15 place-self 某个项目在网络单元(含网格区域)中的对齐方式
16 place-content 项目在网格容器中的对齐方式

三、我所理解的Flex布局和Grid布局。

从上面很明显感觉到Grid布局中对齐方式借鉴了Flex中对齐方式,下面是我找的对应图

对齐方式 flex grid 属性类别
基本概念 弹性容器、弹性项目 网格容器、网格项目
单元 弹性单元??? 网格单元
方向 flex-flow grid-auto-flow 容器属性
单元在容器中对齐 justify-content、align-content place-content 容器属性
所有项目在单元中对齐 align-items place-items 容器属性
项目在单元中对齐 align-self place-self 项目属性

1、对齐方式和排列方向

从上面我不难看出,Flex和Grid二者对齐方式和排列方向,无论是属性名还是取值都非常相似,最大区别是grid是二个值,表示垂直方向和水平方向。处理方式也是两种:所有单元(项目)为一个整体每个为个体来设置对齐方式。整体时取值有flex-start/start、center、flex-end/end和stretch,个体时有space-between,space-around,space-evenly。、

2、弹性单元

上面表格中单元一行,我在Flex项中是问号!!!的确,无论是MDN或是W3C中,flex都没单元的概念,而为什么我写弹性单元呢,一个是我博文《BFC和flex布局探讨和演示》中在探讨align-items和align-content为不为stretch时提出了项目空间的概念,如下图,我得称为弹性单元更合适。

stretch

Flex布局最初是用一维角度来解决问题,但它为了适应变化 ,增加了二维属性,尽管不完美。再用Grid目光来看Flex,Flex就是一行网格或一列网格,它也存在单元的影响,最明显就是align-items为center时,它们是不等高。其实它们弹性单元是等高 。Grid也一样,它等高实质是单元格等高,而不是网格项目等高。

3、Flex对齐方式中不足

Flex布局中对齐方式在二维上是有明显不足的,如一行容纳不下时进行换行,此时对齐方式就是问题,如下图,我想的是换行,第二行应该从起始线开始,但Flex没有网格单元的约束,它就会跑到中间。

grid-flex

4、Flex和Grid布局如何选择

如APP和小程序这样只是一列或一行,推荐先Flex整体布局,再用Grid控制局部布局。而网页端是推荐全部使用Grid布局,如果你想用Flex也可以,它们是可以相互嵌套的。

四、Grid实现栅格化封装

前端想必都熟悉Bootstrap,我当时也是从Bootstrap接触网格概念的。那么用Grid实现一个简单的栅格化系统应该是对Grid最好的总结。至于圣杯三列布局我先给出源码,比较简单就不介绍了

  1. /* 圣杯三列布局: 二边固定,中间自适应 */
  2. <style>
  3. .container {
  4. min-width: 90vw;
  5. min-height: 97vh;
  6. display: grid;
  7. grid-template-columns: 15em 1fr 15em;
  8. grid-template-rows: 3em 1fr 3em;
  9. place-content: center;
  10. gap: 0.5em;
  11. }
  12. header,
  13. footer {
  14. grid-column: span 3;
  15. background-color: lightcyan;
  16. }
  17. </style>
  18. <div class="container">
  19. <header>header</header>
  20. <aside class="left">left</aside>
  21. <main>main</main>
  22. <aside class="right">right</aside>
  23. <footer>footer</footer>
  24. </div>
  1. /* grid实现12列栅格系统 */
  2. .container {
  3. display: grid;
  4. min-width: 90vw;
  5. gap: 0.5em;
  6. }
  7. .container > .row {
  8. display: grid;
  9. grid-template-columns: repeat(12, 1fr);
  10. gap: 0.5em;
  11. }
  12. .container > .row > .item {
  13. padding: 1em;
  14. text-align: center;
  15. }
  16. .col-12 { grid-column: span 12; }
  17. .col-11 { grid-column: span 11; }
  18. .col-10 { grid-column: span 10; }
  19. .col-9 { grid-column: span 9; }
  20. .col-8 { grid-column: span 8; }
  21. .col-7 { grid-column: span 7; }
  22. .col-6 { grid-column: span 6; }
  23. .col-5 { grid-column: span 5; }
  24. .col-4 { grid-column: span 4; }
  25. .col-3 { grid-column: span 3; }
  26. .col-2 { grid-column: span 2; }
  27. .col-1 { grid-column: span 1; }

上面代码修改于老师的代码,后期我会加上我的实现页面,主要是将Flex布局中写的PC端响应式页面转换为Grid。

五、学习后总结

  • 理解Grid布局可以从Excel建表思维来理解画出的网格单元和隐匿网格单元、参考Flex对齐方式理解三种对齐,再结合Flex的方向和table的间隙来理解grid的排列方向和gap间隙。这种方式不知你是否接受,我感觉从上面比较理解了Grid布局
  • Flex可以是看成1.0版的Grid,二者都在相互学习,不过Flex由于一维先天的限制,它无法达到Grid集大成者的水平。但应付目前APP和小程序整体布局还是可以的,尤其是uniapp开发原生APP时是不支持Flex以外布局的。
  • 用老师经常说的话,技术越高级就越接近人的理解思维。从日常的发现来理解复杂的东西,也许不失一种好方法。
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议