CSS Grid网格布局全攻略

全部奇技淫巧都只在方寸之间。css

几乎从咱们踏入前端开发这个领域开始,就不停地接触不一样的布局技术。从常见的浮动到表格布局,再到现在大行其道的flex布局,css布局技术一直在不断地推陈出新。其中网格布局(grid)做为css3的产物,它更加贴近网页设计师所使用的布局策略,学习并利用好它可让咱们免受不少布局困扰。html

虽然网格布局好处有不少,但学习起来并不简单,缘由是用来设置布局的属性实在太多,其中光是做用于父容器的属性就有17种,再加上子元素属性有10种,另外还有这些属性值的不一样取值方式。这些对于记忆来讲绝对是个不小的负担。那么这么多属性以及用法,要如何在短期内消化掉呢?在接下来这篇文章里,我将针对这27种属性以及它们各自的用法,分享我独家的学习策略,但愿对你们的学习有所帮助。前端

布局之道

CSS做为一种网页排版设计语言,其核心的设计思想必然要遵照相关的领域知识。网格布局是一种二维布局结构,它是由纵横相交的两组网格线造成的框架性布局结构。网页设计者能够利用这些由行(row)和列(column)造成的框架性结构来布局设计元素。 在定义一种网格布局结构的时候,咱们须要在父容器上描述要布局的主体框架结构。为了描述这一框架结构,咱们就须要给它的基本构成元素命名。一个网格布局的构成元素能够归纳为如下几种概念:css3

  • row line: 行线
  • column line: 列线
  • track: 网格轨道,即行线和行线,或列线和列线之间所造成的区域,用来摆放子元素
  • gap: 网格间距,行线和行线,或列线和列线之间所造成的不可利用的区域,用来分隔元素
  • cell: 网格单元格,由行线和列线所分隔出来的区域,用来摆放子元素
  • area: 网格区域,由单个或多个网格单元格组成,用来摆放子元素
    grid基本概念

牢记上述这些概念是以后熟练掌握和应用网格布局的基础。算法

构建之法

要熟练掌握一门技术,核心是找到最基本的套路,而后不断练习从而能够在以后的实践过程当中减小决策的时间。因此,这一部分主要就是介绍网格布局构建过程当中的一些经常使用套路。 这里咱们要解决的问题是,如何利用最基本的规则来构建出理想的布局模型。在布局过程当中,归根结底须要处理的就两种页面元素:父容器和子元素。前者主要用来设置基础的布局框架,至关于建筑中的设计蓝图,然后者就是用来进行个性化的布局调整。所以我我的概括了在使用网格布局过程当中的套路是:针对父容器元素进行设置须要三个步骤:定框架、设间隔和找对齐,对子元素来讲有两个步骤:摆位置和找对齐。我把它们统称为**"32构建之法"**。bash

在这一小节中,我将把重心主要放在网格布局中全部用到的27个属性名的讲解上,而取值逻辑将在最后一部分进行统一介绍。微信

父容器

定框架

设置父容器的网格布局的第一步就是将父容器的盒模型设置为grid,这样就能触发渲染引擎的网格布局算法。框架

.parent {
	display: grid;
}
复制代码

接着咱们要开始准备**"画线"**,即设置所需行和列的基础线。这些线条将构成咱们接下来进行布局排布的基础模板(template)。在画线过程当中,咱们须要分别根据行(row)和列(column)两个维度进行设置。你须要画几条线,就设置几个值(不包括边框),其取值是轨道(track)的大小。这里我先画出一个3x3的网格框架,代码以下:wordpress

.parent {
	display: grid;
	grid-template-rows: 100px 100px 100px;
	grid-template-columns: 100px 100px 100px;
}
复制代码

在这里你也能够选择使用缩写形式同时为行和列设置值,采用/分隔开:函数

.parent {
	display: grid;
	grid-template: 100px 100px 100px / 100px 100px 100px;
}
复制代码

image.png

画完线后,下一步咱们能够选择为这些线条和线条之间造成的网格区域(area)进行命名,这样在后续使用的时候就能直接使用这些名字,便于子元素的定位。

.parent {
	display: grid;
	grid-template-areas: "a a b"
	                     "c d e"
	                     "c d ."
}
复制代码

上面这两步画线和命名一样能够采用缩写形式进行设置,代码以下:

.parent {
  	display: grid;
  	grid-template: "a a b" 101px
  	               "c d e" 102px
  	               "c d ." 103px / 104px 105px 105px
}
复制代码

由于使用grid-template同时设置行列和区域名的写法比较复杂,为了讲解方便,我把值设置成规律的递增数字。其中(101, 102,103)设置的是grid-template-rows的值,而(104,105,106)设置的则是grid-template-columns的值。

image.png

到这一步,咱们能够说已经完成所需工做的一大半了。

设间隔

间距(gap)的设置在实际开发中是可选的,主要根据网页设计的需求而定。若是你须要给网格线之间设置间距,咱们能够在行列两个维度上分别进行设置, 下面这段代码将给每一个行和列分别设置10px的间隔:

.parent {
	display: grid;
	grid-template: 100px 100px 100px / 100px 100px 100px;
	grid-row-gap: 10px;
	grid-column-gap: 10px;
}
复制代码

若是采用缩写形式,上述代码又能够简化成:

.parent {
	display: grid;
	grid-template: 100px 100px 100px / 100px 100px 100px;
	grid-gap: 10px 10px;
}
复制代码

设置后的效果以下:

找对齐

有了前面两个步骤,咱们的网格布局框架基本上算是搭建得差很少了。每一个子元素都会默认占据一个网格区域。而在父容器这里咱们若是有须要,就要进行最后一个步骤:找对齐。所谓对齐方式,能够分为内部和外部两种(前者是针对每一个网格区域的子元素而言,然后者是相对于网格区域自己)。另外在行和列(更专业的术语是main axis和cross axis)上又各自有两个维度,这就构成了4种设置对齐的方式。

先来处理一下每一个子元素相对网格区域内部的对齐方式:

.parent {
	display: grid;
	grid-template: 100px 100px 100px / 100px 100px 100px;
	grid-gap: 10px 10px;
	justify-items: center;
	align-items: center;
}
复制代码

在上面的代码中我分别在行和列方向上都设置了居中对齐,这样每一个网格区域中的子元素相对于各自的区域行为是一致的,都能均匀排布。能够看到效果以下图所示:

image.png

再来看一下另外一种状况:

.parent {
	display: grid;
	width: 500px;
	height: 500px;
	grid-template: 100px 100px 100px / 100px 100px 100px;
	grid-gap: 10px 10px;
	justify-content: space-between;
	align-content: center;
}
复制代码

有时候咱们设置的网格不足以覆盖整个父容器的大小时,好比在上述的例子中整个父容器有500px*500px的大小,而咱们只设置了300px*300px的网格区域,这时候就须要指定多出来空间的处理规则。justify-contentalign-content就是分别在行和列两个方向上用来解决这个问题的属性。它们将针对每一个网格区域去设置其在父容器中的对齐方式。

image.png

justifyalign这两个单词在方向上比较容易搞混,因此我在记忆上采起的方式是记住justifyrowaligncolumn这两个合并词,它们长度差很少。若是你有更好的记忆方式,请留言告诉我。

子元素

咱们经过在父容器上搭建好了基础的框架后,对于大部分子元素来讲,就已经可以很好地知足布局要求了。针对部分子元素,能够根据需求进行微调。若是要在子元素上进行布局微调,一般须要如下两个步骤:摆位置和找对齐

摆位置

像下棋同样,针对子元素的排布,咱们须要给它们指定要摆放的具体位置。要肯定具体位置,能够利用以前在父容器中所指定的线名区域名来定位。一种方式是直接经过设置起始行,结束行和起始列,结束列来给子元素划定它所要摆放的区域,另一种方式是指定要摆放的区域名。

/* 指定起始行,结束行,起始列,结束列 */
.child:first-child {
    grid-row-start: 1;
    grid-row-end: 2;
    grid-column-start: 1;
    grid-column-end: 3;
    background: red;
}

/* 使用缩写形式 */
.child:nth-child(2) {
	grid-row: 2/3;
	grid-column: 2/4;
	background: yellow;
}

/* 直接指定区域名 */
.child:nth-child(3) {
	grid-area: i;
	background: green;
}
复制代码

这段代码的效果以下:

image.png

还有一种更加灵活的设置位置方式,是指定跨越的行数和列数,关键字span用来控制一次跨越的行数或列数, 如上面第三个子元素能够改写成:

.child-nth-child(3) {
  grid-row: 2/3;
  grid-column: span 2;
}
复制代码

找对齐

和父容器中所设置的对齐方式相似,针对个别子元素的对齐处理,咱们能够按照行列两组属性进行分别处理:

/* 列对齐 */
.child:nth-child(1) {
  align-self: end;
}

/* 行对齐 */
.child:nth-child(2) {
  justify-self: end;
}

/* 采用缩写形式 */
.child:nth-child(3) {
  place-self: center center;
}
复制代码

image.png

*隐式网格

灵活性是网格布局的一大优点,除了采用上述那种手动指定框架结构的方式,网格布局还有一套自动化布局的机制,这套机制称为**“隐式网格布局”**。当咱们在网格定义的区域外放置子元素时,或因子元素数量过多而须要更多的网格线时,布局算法就会自动生成隐式网格。默认状况下这些隐式网格的大小也会随着内容尺寸不一样而变化,而咱们能够利用属性grid-auto-rowsgrid-auto-columns来控制隐式网格的大小。 考虑下面这个例子:

<div class="parent">
  <div class="child" style="background: red"></div>
  <div class="child" style="background: yellow"></div>
  <div class="child" style="background: green"></div>
</div>
复制代码
.parent {
  display: grid;
  grid-auto-rows: 100px;
  grid-auto-columns: 100px;
}
复制代码

经过手动在父容器中设置隐式网格大小为100x100的大小后,效果以下:

image.png
若是子元素引用了不存在的行号和列号,父容器会自动生成隐式网格以容纳全部子元素:

.child:first-child {
    grid-row-start: 1;
    grid-row-end: 2;
    grid-column-start: 1;
    grid-column-end: 3;
    background: red;
}
复制代码

image.png

有了网格大小的控制,咱们还须要位置的控制。默认状况下,子元素都是先将行填充满,容器大小不够的时候才会生成新的隐式行。若是要改变这一默认行为,咱们须要使用grid-auto-flow属性来控制:

.parent {
  display: grid;
  grid-auto-rows: 100px;
  grid-auto-columns: 100px;
  grid-template-areas: "a b c" "d e f" "g h i";
  grid-auto-flow: column;
}
复制代码

image.png

取值之术

介绍完全部的网格布局属性后,咱们再来讲一下各类属性的取值策略。

大小

在CSS中,咱们一般使用px,em等取值单位进行属性大小的设置,对于灵活的布局需求来讲,百分比也是经常使用的取值单位。这些单位在日常工做中彷佛已经足够用了。不过,为了让布局可以更加灵活,网格布局中引入了一种新单位fr,它是fraction这个单词的缩写,意思是容器内剩余空间的分数比。考虑下面这个例子:

.parent {
  height: 100px;
  display: grid;
  grid-template-columns: 100px 1fr 100px;
}
复制代码

咱们经过设置100px 1fr 100px的布局框架,从而很轻松地就实现了两边宽度固定,中间自适应的效果。

image.png

若是要实现有比例关系的布局结构,还可使用多个fr的取值:

.parent {
  width: 400px;
  height: 100px;
  display: grid;
  grid-template-rows: 100px 1fr 100px;
  grid-template-columns: 1fr 1fr 2fr;
  grid-template-areas: "a b c"
}
复制代码

能够看到区域a,b,c之间的比例关系就是"1:1:2"的关系。

image.png

除了上述这个支持自适应的单位外,网格布局中还可以使用max-contentmin-content这组关键字来达到自适应的目的。要理解这两个关键字,首先须要理解内在尺寸(intrinsic size)和外部尺寸(extrinsic size)这两个概念。先说一下extrinsic size,它的相对值计算是相对于父容器对应的属性值。咱们知道,width若是使用百分比单位,其计算值是相对于该元素所在的容器宽度的,好比父容器宽度100px, 子元素设置width: 20%,那么它的宽度就是100px * 20% = 20px。在css3中引入了intrinsic size则是相对于元素自身尺寸进行计算。max-contentmin-content就是相对于元素自身内容块进行计算的属性值。

min-content顾名思义是根据元素内容来设置的最小宽度大小,在英文句子中,一般是最长单词的那个长度,而中文中则是一个字的长度。好比下面这个例子:

.parent {
  display: grid;
  grid-template-columns: auto min-content auto;
}
复制代码

image.png

能够看到,中间那个网格的那个宽度就等于scq000这个单词的长度。

min-content相对应,max-content会将尺寸设置成内容尺寸能达到的最大宽度。咱们把代码改为下面这样:

.parent {
  display: grid;
  grid-template-columns: auto max-content auto;
}
复制代码

image.png

有了这两个属性值,咱们能够很容易地让布局区域根据内容进行自适应。

函数

函数是用来避免重复性工做的一种有效工具,在网格布局中提供了一些经常使用CSS函数来方便咱们的工做。

第一个要介绍的是minmax这个函数。在设置网格框架的过程当中,对于自适应的网格区域,咱们都会设置一个最小值和最大值,这个函数就是用来实现这个目的的。

.parent {
    display: grid;
    grid-template-columns: 100px minmax(100px, 200px) 100px;
}

/* 最经常使用的状况是只设置最小,不设置最大值 */
.parent {
    display: grid;
    grid-template-columns: 100px minmax(100px, auto) 100px;
}
复制代码

利用这个函数设置的网格布局能够作到很好的自适应,在页面伸缩过程当中也能保证布局的稳定性。

另外一个颇有用的函数是fit-content,它其实是min(maximum size, max(minimum size, argument))的简写,表示将元素宽度收缩到内容宽度。说得通俗点就是,使用这个函数后会尽可能不占用多余的空间。若是内容的宽度小于fit-content中设置的长度,那么实际子元素宽度是内容宽度。若是内容宽度超出了fit-content中设置的长度,那么实际子元素宽度就是设置的那个长度。下面看两个例子:

.parent {
    display: grid;
    grid-template-rows: auto fit-content(200px) auto;
}
复制代码

image.png

image.png

第一个句子中的长度超出了200px,那么此时中间网格的宽度是200px。而第二个例子中内容宽度不足200px,此时中间网格的宽度是句子实际占用的宽度。

最后要介绍的是repeat函数,它主要用来批量设置框架的间距,这个函数接受两个参数,第一个参数控制循环次数,第二个参数控制间距大小。让咱们用这个函数改写一下上述例子:

.parent {
	display: grid;
	grid-template-rows: 100px 100px 100px;
	grid-template-columns: 100px 100px 100px;
}
/* 利用repeat函数改写 */
.parent {
	display: grid;
	grid-template-rows: repeat(3, 100px);
	grid-template-columns: repeat(3, 100px);
}
复制代码

另外,第一个参数除了可使用数字显示设置网格数量外,还能使用auto-fitauto-fill两个关键字自动分配空间。一般状况下,这两个关键字的使用效果都差很少,惟一的差异是空余空间的分配规则。搭配minmax函数能够看出区别,以下面这两个例子:

.parent {
	display: grid;
	width: 500px;
	height: 100px;
	grid-gap: 10px;
	grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}

.parent {
	display: grid;
	width: 500px;
	height: 100px;
	grid-gap: 10px;
	grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
}
复制代码

auto-fit

image.png

在单行布局的时候,若是有空余空间auto-fit会将它们平均分配到全部子元素中,而auto-fill会自动建立空白的列。

命名

咱们在建立网格布局框架的时候,经过"画线"来指定基本布局结构。默认状况下,网格布局会给每一条网格线进行命名,命名顺序同书写顺序一致:从左到右,由上至下按数字命名。假设咱们指定的是3x3的网格布局结构,那么包含边框线,就会生成4+4=8条线。

image.png
除了采用默认命名方式,咱们还可以自定义网格线的名称以便于后续在子元素定位中使用。

.parent {
  display: grid;
  grid-template-rows: [row-a] 100px [row-b] 100px [row-c] 100px [row-d];
}
复制代码

对齐

对齐是布局过程当中一个不可缺乏的步骤,它的取值是经过已有的关键字来指定的。其中用于网格布局中对齐的关键字有start,center, endstretch四个。 咱们先从默认值stretch看起,这个关键字是伸展的意思,因此在默认状况下网格中的子元素会尽量地填充满网格区域,因为是默认值因此日常写代码的时候就不太会能够去用这个关键字进行声明。 接着再来看一下经常使用的对齐取值策略,只须要记住一点就能够了:用属性justify-*,align-*来分别控制横轴和纵轴两个方向,属性值控制其对齐位置。 startcenterend三个属性值就分别对应了前中后三个位置。

.parent {
  display: grid;
}
.child:first-child {
  justify-self: start;
}
.child:first-child {
  justify-self: center;
}
.child:first-child {
  justify-self: end;
}
复制代码

*排列

让咱们从新回到隐式网格那部分,隐式的排列规则是经过指定grid-auto-flow这个属性来设置的。它的取值只有三个rowcolumndense。上面属性部分已经介绍过rowcolumn两个属性值,前者是按行优先来摆放子元素,后者是按列优先来摆放子元素。这里主要介绍一下dense这个属性值。一般状况下,排列子元素会按照顺序填充行或列,若是空间不足的时候,会换行或换列。而使用了dense属性后,会尽可能使用空余空间,考虑下面这段代码:

.parent {
  display: grid;
  grid-template-columns: repeat(3, 100px);
}
复制代码
<div class="parent">
  <div class="child">1</div>
  <div class="child">2</div>
  <div class="child">3</div>
  <div class="child">4</div>
  <div class="child">5</div>
</div>
复制代码

默认状况下,显示效果是这样的:

image.png

当咱们使用dense值进行排列的时候,就至关于开启“紧凑”模式,会尽量利用空余空间。

.parent {
	display: grid;
	grid-auto-flow: row dense;
	/* 因为默认为按行排列,可省略为dense */
	grid-auto-flow: dense;
}
复制代码

因此,显示效果以下:

image.png

总结

在这篇文章里,我经过拆解分类全部网格布局相关的知识点,但愿可以为你们提供一个比较系统的运用网格布局的指导方法。在实际应用过程当中,沿着"32构建之法”的这个套路来走,能够节约不少思考和决策时间。另外,因为这篇文章信息密度可能比较大,但愿你们可以多多复习,并跟着例子实际操练几遍,这样在实际工做运用中才能如鱼得水。最后,送上一张思惟导图,帮助你们可以一览本文全部的重点。

image.png

推荐阅读

grid.malven.co/

www.w3.org/TR/css-alig…

medium.com/@patrickbro…

www.zhangxinxu.com/wordpress/2…

css-tricks.com/difference-…

画图调试工具: www.mozilla.org/en-US/firef…

——本文首发于我的公众号,转载请注明出处———

微信扫描二维码,关注个人公众号
最后,欢迎你们关注个人公众号,一块儿学习交流。
相关文章
相关标签/搜索