关于 Grid 布局的那点事儿

相信大部分前端小伙伴已经有过使用 Grid 布局的体验,一定是美滋滋。Flex 布局和 Grid 布局作为 CSS 布局领域的两大新星,可谓是拥护者甚众。我在前面这篇文章中总结了 Flex 布局的强大之处,今天再来总结一下 Grid 布局的基础知识。

基本介绍

Grid 布局在 2017 年开始已经逐渐获得各大主流浏览器的支持,虽然暂时无法在生产环境中运用,但是它作为一项令所有 UI 工程师欢欣鼓舞的技术,是值得马上去了解它的奥妙的。为了获得更好的调试体验,我们可以在 FireFox 浏览器中学习它(FireFox 的开发者工具对它的支持很友好)。

那么,它与传统的布局方案,包括前面介绍的 Flex 布局方案相比的特性在于:

  • 它是第一个真正意义上的布局系统,其主要表现在它是第一个基于二维方向的布局模块
  • 它是第一个基于网格(或者叫栅格,本文叫网格)的原生布局系统

所谓基于二维方向,是指它可以针对水平和垂直方向两个维度上进行布局设计。在它之前,我们的布局方案,只能在水平方向上进行布局,对于垂直方向则无能为力,而 Grid 则可以轻松地实现二维布局。

那么,什么是网格呢?我们可以这样理解,网格是由一组水平和垂直的直线交叉,形成一个个矩形区域,我们可以将元素放置在这些区域中,这样的好处是,元素可以很好地控制和对齐。

可以说,我们以前采取的布局方案,其实是工程师们没法子想出来的办法,毕竟 position,display 等属性,并不是为了布局而生的。而 CSS Grid,才是一个真正的布局系统。

核心概念

了解了 CSS Grid 布局的优越性,我们马上来了解如何运用这项技术。

和 Flex 类似,Grid 的使用同样简单,第一步,我们需要把某个容器指定成网格容器:

.grid {
    display: grid || inline-grid;
}

这个时候,.grid 就变成了一个 网格容器(Grid Conatainer),包含在这个容器中的子元素则自动变成了 网格项(Grid Items), Grid 的所有属性都在两个概念之间展开。

下面这张图,就是一个网格容器中,包含着 9 个网格项。

Grid 示意

上面这个等宽的三行三列的布局,如何实现呢?在传统方案中,我们可能需要借助浮动属性等来实现,但是借助 Grid ,就很简单了,在为父元素指定 display: grid; 之后,我们可以借助两个属性: grid-template-columns, grid-template-rows 和一个新单位 fr 来轻松实现。

.grid {
    display: grid; 
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr;
    grid-gap: 20px 10px;
}

grid-template-columnsgrid-template-rows 分别表示水平方向上和垂直方向上网格项的空间分配比例,fr 是一个新单位,表示占据可用空间的一等分。所以上面的代码表示,在水平和垂直方向分别把可用空间分为三份,且三份占据空间相等。grid-gap 属性指的是网格项之间的间隙,后面会介绍到。

学习到了这两个属性,我们已经可以轻松地布局出常见的多栏布局,例如我们要实现一个水平为 1:2:1 的布局,可以这样实现:

.grid {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    grid-gap: 10px;
}
grid 实现 1-2-1 三栏布局

当然我们同样可以为上面的属性设置固定的长度,例如像素值。

Grid 布局为我们提供一个 repeat() 函数来更高效地实现复杂的布局,它可以接收两个值,第一个值是重复的数量,第二个值是重复的模式,例如:repeat(3, 1fr) 表示三等分的布局,repeat(3, 1fr 200px)表示把1fr 加一个200px的布局重复三次。

以上的赋值形式可以混杂来使用,例如:

grid-template-columns: 200px 1fr repeat(3, 100px);

上面的布局从左到右呈现为:200px 1fr 100px 100px 100px.

grid-auto-columns grid-auto-rows

在我们没有显示地借助前面的 grid-template-columnsgrid-template-rows 来指定网格项的空间分配方式的时候,我们可以使用 grid-auto-columnsgrid-auto-rows 两个属性来设置网格区域的自动显示范围,经常可以借助一个工具函数 minmax() 来指定,例如 grid-auto-rows: minmax(120px, auto),表示不管网格区域中有没有内容,其高度最小为 120px,如果其有超过 120px 的部分的内容,则自动扩张。

网格线(Grid Line)

所谓网格线,就是两个网格轨道之间以及网格边缘的直线,在上面这个三行三列的网格中,水平和竖直方向上各有四条网格线,在 Grid 中,我们通常按照书写方向,为这些网格线编号,水平方向上,我们从左至右,将它们编号为 “1, 2, 3, 4···”,竖直方向上同理,从上往下编号,如下图所示:

网格线

网格轨道(Grid Track)

网格轨道指的是任意两条网格线之间的空间(这条线不一定看得见),在上面的图片中,我们可以清晰地看到水平和竖直方向上黑线之间的网格轨道,而我们的网格项就是在这些轨道上安放。

网格区域(Grid Area)

网格区域,就是若干个相邻的网格单元组成的区域,我们可以通过组合网格单元来创建出不同大小的网格区域。

下面为了不致混乱,我们分网格容器和网格项来说明它们上面可以设置的属性。

网格容器上可以设置的属性有(因为二维布局,基本来说,某一个针对水平方向的属性,同样有一个数值方向的属性与之相对应,为了方便,我们一起介绍它们):

  1. display: grid || inline-grid || subgrid
  2. grid-template-columnsgrid-template-rows
  3. grid-auto-columnsgrid-auto-rows
  4. grid-auto-flow
  5. grid-column-gapgrid-row-gap 以及两者合写 grid-gap
  6. justify-items
  7. align-items
  8. justify-content
  9. align-content
  10. grid-template-area

网格项上面可以设置的属性有:

  1. grid-column-start
  2. grid-column-end
  3. grid-row-start
  4. grid-row-end
  5. grid-column(1 和 2 的合写形式)
  6. gird-row(3 和 4 的合写形式)
  7. grid-area
  8. justify-self
  9. align-self

别看上面的属性很多,其实读者完全不必慌,一则是这些属性中高频使用的就几个,二者是上面好几组属性完全可以用它们的缩写形式来替代。下面来介绍其中高频使用的一些属性(更详细的大家可以在 MDN 上查看详情介绍),前面已经了解的部分不再赘述。

grid-gap

grid-gap 用来设置网格间距,也就是两个网格之间留出来的空白,其可以在横向和纵向分别通过 grid-column-gapgrid-row-gap 来设置相应的大小,这两个属性值通常可以合写为 grid-gap

.grid {
    grid-gap: 20px 10px;
}

在横向设置 10px 的间距,纵向设置 20px 的间距,如果,横向和纵向要设置的大小一致时,可以直接缩写为一个值: grid-gap: 20px;

我们可以从这张图上看到这些概念。

网格核心概念

grid-template-areas

这个属性十分方便,可以通过指定网格单元的名字来定义一个网格模板,然后在网格项上面使用 grid-area 属性与之配合,来确定其显示的区域。重复相同的网格单元的名字,就会自动合并两个单元,可以使用一个句点 . 来表示一个空白的网格单元。例如以下的一个布局形式:

grid-area

代码:

.grid {
    display: grid;
    grid-gap: 10px;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-areas: "header header header"
                         "siderbar content content"
                         "footer footer footer"
}

.one {
    grid-area: header;
}

.two {
    grid-area: siderbar;
}

.three {
    grid-area: content;
}

.four {
    grid-area: footer;
}

通过实例我们可以看到,在网格容器上,我们为其定义网格区域的显示模板,然后在相应的网格项上将设置好的 grid-area-name 赋值给 grid-area 属性,这样就可以很便捷地达到我们的效果。

justify-itemsalign-items

我们知道在 Flex 布局中,可以借助 justify-content 以及 align-items 来设置弹性项目在水平和竖直方向的对齐方式,强大的 Grid 系统自然也可以进行设置,其属性和 Flex 很相似,分别使用 justify-itemsalign-items(后者和 Flex 一致有没有)。不同的是,这两个属性的属性值是参照网格线来确定它们的位置:

.grid {
    justify-items: start | end | center | stretch;
}

属性值介绍:

  • stretch: 默认值,内容充满整个网格区域
  • start:网格项内容与网格区域左侧对齐
  • end: 网格项内容与网格区域右侧对齐
  • center: 网格项内容在网格区域居中显示

align-items 与前者相同道理,不再赘述。如果在前面的例子中,我们将这两个属性值设置为 center, 则它们就会呈现为下面这幅样子:

justify-items 和 align-items

gird-columngrid-row

除了在网格容器上统一进行的设置,我们可以针对特定的网格项进行设置,决定其占据的网格区域,我们可以借助网格线的约束,来决定某一个网格项的空间。例如,我们想要实现一个元素占据水平方向从第 1 条网格线到第 3 条网格线,竖直方向从第 2 条网格线到第 4 条网格线,也就是下面红色元素的位置:

跨轨道放置元素

如何实现呢,水平方向借助这两个属性:grid-column-start, grid-column-end,分别表示该网格项开始和结束的网格线序号,其值是代表网格线的编号。

.item1 {
    grid-column-start: 1;
    grid-column-end: 3
}

竖直方向同理,使用 grid-row-startgrid-row-end 两个属性实现:

.item1 {
    grid-row-start: 2;
    grid-row-end: 4;
}

如此一来,就可以实现上面图中的效果,这两组属性同样有相应的缩写形式,我们把 grid-column-start, grid-column-end 合写为 grid-column,把 grid-row-startgrid-row-end 合写为 grid-row,其值用一个 / 来分隔。

grid-column: 1/3;
grid-row: 2/4;

justify-selfalign-self

这两个属性用来设置特定网格项目在其网格区域中的对齐方式,其可取的属性值与 justify-itemsalign-items 相同。不再说明。

更改重叠区域的层级顺序

当两个网格区域在空间上发生重叠之时,其层叠顺序按照其在 DOM 结构中的出现前后决定,后来者会居上。如果我们想人为改变这些重叠次序,可以为相应的区域设置 z-index 属性,来改变它的层叠优先级,这和定位元素的设置一致。

以上就是 Grid 布局的基本概念,我们可以看到,最常用的几个属性是:grid-template-* 相关的几个属性,用来指定网格区域留白的 grid-gap,以及用来声明网格项目在各自网格区域中的对齐方式的 align-items 以及 justify-items 两个属性。在网格项上,用来指定网格项显示区域的 grid-column 以及 grid-row 属性,指定特定网格项在其网格区域中对齐方式的 align-selfjustify-self 属性。用熟了这些属性,Grid 布局的使用自然是手到擒来,至于其它更复杂的属性,在后来的学习中循序渐进使用并熟悉。文中有什么疏漏和错误之处,希望大家指正。

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 简介CSS网格布局(又称“网格”),是一种二维网格布局系统。CSS在处理网页布局方面一直做的不是很好。一开始我们用...
    _leonlee阅读 64,933评论 25 173
  • 简介 CSS Grid布局 (又名"网格"),是一个基于二维网格布局的系统,旨在改变我们基于网格设计的用户界面方式...
    咕咚咚bells阅读 2,486评论 0 4
  • 转载地址:https://www.cnblogs.com/xiaohuochai/p/7083153.html 前...
    One_Hund阅读 1,302评论 0 1
  • Grid 是CSS中最强大的布局系统。它是2-Dimensional System,这意味着它可以同时处理列和行....
    邢烽朔阅读 2,577评论 0 5
  • 前戏 没有前戏。。。。。真的没有。 Grid布局简介 不多bb先丢个文档上来(嗯) 网格布局 - CSS | MD...
    clancysong阅读 1,919评论 0 1