前端开发者学堂 - fedev.cn

学习CSS Grid

发布于 大漠

CSS Grid是一个强大的工具,它允许在Web上创建二维布局。这一篇学习CSS Grid的指南,通过图形的方式帮助您更好的理解和学习CSS Grid。花时间整理和阅读这篇文章都是非常有意义的。

我们要特别感谢Mozilla开发人员W3C规范中有关于CSS Grid的资源。同时也需要特别感谢@Jen Simmons@Rachel Andrews两位女士,她们是CSS Grid的主要贡献者,可以说要是没有她们,就没有今天的CSS Grid。

网格容器

通过display属性设置属性值为gridinline-grid可以创建一个网格容器。网格容器中的所有子元素就会自动变成网格项目(grid item)。

display: grid

网格项目默认放在行中,并且跨网格容器的全宽。

display: inline-grid

显式网格

使用grid-template-columnsgrid-template-rows属性可以显式的设置一个网格的列和行。

grid-template-rows: 50px 100px

grid-template-rows指定的每个值可以创建每行的高度。行高的尺寸可以是任何非负值,长度可以是px%em等长度单位的值。

item1item2具有固定的高,分别为50px100px

因为只定义了两个行的高度值,所以item3item4的高度是根据其自身的内容来定义。

grid-template-columns: 90px 50px 120px

像行一样,通过grid-template-columns指定的每个值来创建每列的列宽。

item4item5item6放置在新的一行(第二行),因为grid-template-columns只定义了三列的大小,它们也分别放置在列1、列2和列3;其中列1、列2和列3的尺寸大小等于item1item2item3宽度。

item1item2item3具有固定的宽度值,分别为90px50px120px

grid-template-columns: 1fr 1fr 2fr

fr单位可以帮助我们创建一个弹列的网格轨道。它代表了网格容器中可用的空间(就像Flexbox中无单位的值)。

在这个示例中,网格容器分成了4等份(1 + 1 + 2 = 4),每一份(1fr)是网格容器宽度的四分之一。所以item1item2的宽度是网格容器的四分之一宽,item3是网格容器宽度的四分之二(2fr)。

grid-template-columns: 3rem 25% 1fr 2fr

fr和其它长度单位的值结合在一起的时候,fr是基于网格容器可用空间来计算。

在这个示例中,网格容器可用空间是网格宽度减去3rem25%剩下的宽度,而fr就是基于这个尺寸计算:

1fr = (网格宽度 - 3rem - 网格宽度 * 25%) / 3

网格轨道最小和最大尺寸

可以通过minmax()函数来创建网格轨道的最小或最大尺寸。

grid-template-rows: minmax(100px, auto);
grid-template-columns: minmax(auto, 50%) 1fr 3em;

minmax()函数接受两个参数:第一个参数定义网格轨道的最小值,第二个参数定义网格轨道的最大值。可以接受任何长度值,也接受auto值。auto值允许网格轨道基于内容的尺寸拉伸或挤压。

在这个示例中,第一行的高度最小值是100px,但其最大值为auto,允许行高可以变大超过100px

第一列设置了最小值为auto,但它的最大值是50%,也就是列的最大宽度不会超过网格容器宽度的50%

重复网格轨道

使用repeat()可以创建重复的网格轨道。这个适用于创建相等尺寸的网格项目和多个网格项目。

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

repeat()也接受两个参数:第一个参数定义网格轨道应该重复的次数,第二个参数定义每个轨道的尺寸。

grid-template-columns: 30px repeat(3, 1fr) 30px

repeat()也可以用在轨道列表中。

在这个示例中,第一列和最后一列的宽度都是30px,并且它们之间有另列三列,这三列是通过repeat()来创建的,而且每列的列宽是1fr1fr = (网格宽度 - 30px - 30px) / 3)。

间距

grid-column-gapgrid-row-gap属性用来创建列与列,行与行之间的间距。

grid-gap只能创建列与列或行与行之间的间距,但不能创建列和行与网格容器边缘的间距。

grid-row-gap: 20px;
grid-column-gap: 5rem;

间距(Gap)可以设置任何非负值,长度值可以是px%em等单位值。

grid-gap: 100px 1em;

grid-gapgrid-row-gapgrid-column-gap两个属性的缩写。

如果它指定了两个值,那么第一个值是设置grid-row-gap的值,第二个值设置grid-column-gap的值。

grid-gap: 2rem;

如果只设置了一个值,表示行和列的间距相等,也就是说grid-row-gapgrid-column-gap的值都相同。

通过网格线号码来定位网格项目

网格线实际上是代表线的开始、结束,两者之间就是网格列或行。

每条线是从网格轨道开始,网格的网格线从1开始,每条网格线逐步增加1

grid-row-start: 2;
grid-row-end: 3;
grid-column-start: 2;
grid-column-end: 3;

两列三行的网格创建三条列网格线和四条行网格线。item1就是由行和列的号码重新定位。

如果一个网格项目跨度只有一行或一列,那么grid-row-endgrid-column-end不是必需的。

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

grid-rowgrid-row-startgrid-row-end的简写。grid-columngrid-column-startgrid-column-end的简写。

如果只提供一个值,他指定了grid-row-startgrid-column-start的值。

如果提供两个值,第一个值是grid-row-startgrid-column-start的值,第二个值是grid-row-endgrid-column-end的值,两者之间必须要用/隔开。

grid-area: 2 / 2 / 3 / 3;

如果指定四个值,第一个值对应grid-row-start,第二个值对应grid-column-start,第三个值对应grid-row-end和第四个值对应grid-column-end

网格项目跨行或跨列

默认情况下网格项目跨度只有一个列和行,但可以跨越多个行和列。

grid-column-start: 1;
grid-column-end: 4;

可以通过设置grid-column-endgrid-column-start距离多个网络线号实现多个列跨越。

grid-row-start: 1;
grid-row-end: 4;

同样的可以通过grid-row-endgrid-row-start距离多个网格号实现多个行跨越。

grid-row: 2 / 5;
grid-column: 2 / 4;

通过简写的grid-rowgrid-column也能实现多行或多列的跨越。

grid-row: 2 / span 3;
grid-column: span 2;

关键词span后面紧随数字,表示合并多少个列或行。

网格线命名

通过grid-template-rowsgrid-template-columns定义网格时,网格线可以被命名。网格线名称也可以设置网格项目位置。

grid-template-rows:    [row-1-start] 1fr [row-2-start] 1fr [row-2-end];
grid-template-columns: [col-1-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-3-end];

grid-template-rowsgrid-template-columns定义你的网格,将名称分配给网格线。

定义网格线名称时需要避免使用规范中出现的关键词,以免导致混乱。

分配网格线名称必须用方括号[网格线名称],然后后面紧跟网格轨道的尺寸值。

grid-template-rows:    [row-start row-1-start] 1fr [row-1-end row-2-start] 1fr [row-2-end row-end];
grid-template-columns: [col-start] 1fr [col-2-start] 1fr [col-3-start] 1fr [col-end];

可以在方括号中添加多个名称来命名网格线名称,使用多外名称命名网格线名称时,名称间要用空格隔开。

每一个网格线的名称可以用来定位网格项目的位置。

通过网格线名称设置网格项目位置

使用网格线名称设置网格项目位置和使用网格线号码设置网格项目位置类似。

grid-row-start:    row-2-start;
grid-row-end:      row-end;
grid-column-start: col-2-start;
grid-column-end:   col-end;

引用网格线名称的时候不应该带方括号。

grid-row:    row-2-start / row-end;
grid-column: col-2-start / col-end;

grid-rowgrid-column简写属性也适用于网格线名称,也可以用来设置网格项目的位置。

使用相同的名称命名网格线和设置网格项目位置

使用repeat()函数可以给网格线分配相同的名称。这可以节省一定的时间。

grid-template-rows: repeat(3, [row-start] 1fr [row-end]);
grid-template-columns: repeat(3, [col-start] 1fr [col-end]);

使用repeat()函数可以给网格线命名,这也导致多个网格线具有相同的网格线名称。

相同网格线名称指定网格线的位置和名称,也且会自动在网格线名称后面添加对应的数字,使其网格线名称也是唯一的标识符。

grid-row:    row-start 2 / row-end 3;
grid-column: col-start / col-start 3;

使用相同的网格线名称可以设置网格项目的位置。网格线的名称和数字之间需要用空格分开。

在这个示例中,item1放置位置是row-start2条开始,至row-end的第3条结束,这用来设置item1在行的起始和结束位置;col-start的第1条开始,至col-start的第3条结束(col-start的第3条也对应的是col-end的第2条),用来设置item1在列的起始位置和结束位置。

通过网格区域命名和定位网格项目

像网格线名称一样,网格区域的名称也可以使用grid-template-areas属性来命名。引用网格区域名称也可以设置网格项目位置。

grid-template-areas:   "header header"
                        "content sidebar"
                        "footer footer";
grid-template-rows:    150px 1fr 100px;
grid-template-columns: 1fr 200px;

设置网格区域的名称应该放置在单引号或双引号内,每个名称由一个空格符分开。

网格区域的名称,每组(单引号或双引号内的网格区域名称)定义了网格的一行,每个网格区域名称定义网格的一列。

grid-row-start:    header;
grid-row-end:      header;
grid-column-start: header;
grid-column-end:   header;

grid-row-startgrid-row-endgrid-column-startgrid-column-end可以引用网格区域名称,用来设置网格项目位置。

grid-row:    footer;
grid-column: footer;

简写的grid-rowgrid-column也可以引用网格区域名称,设置网格项目的位置。

grid-area: sidebar;

grid-area简写属性也可以引用网格区域的名称来设置网格项目的位置。

隐式网格

当网格项目确认在显式网格之外时就会创建隐性网格,当没有足够的空间或者显式的网格轨道来设置网格项目,此时网格项目就会自动创建隐式网格。

使用grid-auto-rowsgrid-auto-columnsgrid-auto-flow属性可以定义隐式的网格。

grid-template-rows:    70px;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows:        140px;

在这个例子中我们只定义了一行(轨道),所以item1item2的高都是70px

第二行(轨道)自动创建了item3item4空间。grid-auto-rows定义隐式网格中的行(轨道)的大小,因此item3item4的高度是140px

grid-auto-row: row

网格默认流方向是row

grid-auto-flow: column

也可以把网格流的方向改变成column

grid-template-columns: 30px 60px;
grid-auto-flow:        column;
grid-auto-columns:     1fr;

在这个例子中,我们只定义了前两列的轨道尺寸。item1的尺寸是30pxitem2的尺寸是60px

使用grid-auto-flow:column自动创建了隐式网格,用来放置item3item4item5,并且这三个列(轨道)的尺寸由grid-auto-columns来定义。

隐式地命名网格区域名称

通常可以将网格线命名成任何你想命名的名称,如果网格线名称添加-start-end的后缀,其实也隐式的创建一个网格区域,可以用来设置网格项目的位置。

grid-template-rows:    [outer-start] 1fr [inner-start] 1fr [inner-end] 1fr [outer-end];
grid-template-columns: [outer-start] 1fr [inner-start] 1fr [inner-end] 1fr [inner-end];

在这个示例中,行和列都具有inner-startinner-end网格线名称,同时也对应的创建一个隐式网格区域名称inner

grid-area: inner

网格项目定位可以通过网格区域名称来设置,而不需要使用网格线名称。

隐式命名网格线名称

隐式的指定网格线反向指定了隐式的网格区域名称,命名的网格区域隐式的命名了网格线名称。

grid-template-areas:   "header header"
                        "content sidebar"
                        "footer footer";
grid-template-rows:    80px 1fr 40px;
grid-template-columns: 1fr 200px;

指定网格区域会给网格区域边线添加隐式的网格线名称。这些网格线的命名是基于网格区域来命名,只是在网格区域名称的后面添加后缀-start-end

grid-row-start:    header-start;
grid-row-end:      content-start;
grid-column-start: footer-start;
grid-column-end:   sidebar-end;

在这个示例中,header通过隐式的网格线名称设置其位置。

网格项目层级

网格项目可以具有层级和堆栈,必要时可能通过z-index属性来指定。

.item-1,
.item-2 {
    grid-row-start:  1;
    grid-column-end: span 2;
}

.item-1 { 
    grid-column-start: 1; 
    z-index: 1; 
}
.item-2 { 
    grid-column-start: 2 
}

在这个例子中,item1item2的开始行都是1item1列的开始是1item2列的开始是2,并且它们都跨越两列。两个网格项目都是由网格线数字定位,结果这两个网格项目重叠了。

默认情况下,item2item1上面,但是,我们在item1中设置了z-index:1;,导致item1item2之上。

grid-row-start:    header-start;
grid-row-end:      content-end;
grid-column-start: content-start;
grid-column-end:   sidebar-start;
z-index: 1;

在这个示例中,一个网格项目定位和分层使用了grid-template-areas定义的隐式网格线的名称。

网格项目对齐方式(Box Alignment)

CSS的Box Alignment Module补充了网格项目沿着网格行或列轴对齐方式。

justify-itemsjustify-self指定网格项目沿着行轴对齐方式;align-itemsalign-self指定网格项目沿着列轴对齐方式。

justify-itemsalign-items应用在网格容器上,它们的属性值有:

  • auto
  • normal
  • start
  • end
  • center
  • stretch
  • baseline
  • first baseline
  • last baseline

.grid {
    grid-template-rows: 80px 80px;
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "content content"
                    "content content";
}
.item { 
    grid-area: content 
}

.grid {
    justify-items: start
}

网格项目定位在行轴的开始位置(行网格线1)。

justify-items: center

网格项目定位在行轴的中间。

justify-items: end

网格项目定位在行轴末端。

justify-items: stretch

网格项目横跨整个行轴,stretchjustify-items的默认值。

align-items: start

网格项目定位在网格列轴的开始位置(列网格线1)。

align-items: center

网格项目定位在网格列轴中间。

align-items: end

网格项目定位在网格列轴末端。

align-items: stretch

网格项目横跨整个列。

justify-items: center
align-items:   center

网格项目定位在网格行和列的中间(实现水平垂直居中)。

align-selfjustify-self属性用于网格项目自身对齐方式。它们主要接受以下属性值:

  • auto
  • normal
  • start
  • end
  • center
  • stretch
  • baseline
  • first baseline
  • last baseline

.item-1 { 
    justify-self: start 
}
.item-2 { 
    justify-self: center 
}
.item-3 { 
    justify-self: end 
}

justify-selft指定网格项目自身沿着网格行轴的对齐方式。

.item-1 { 
    align-self: start 
}
.item-2 { 
    align-self: center 
}
.item-3 { 
    align-self: end 
}

align-self指定网格项目自身沿着列轴的对齐方式。

.item-1 {
    justify-self: center
    align-self:   center
}

item1项目定位在网格行和列轴的中间(实现水平垂直居中)。

网格轨道对齐方式

网格轨道对齐可以相对于网格容器行和列轴。

align-content指定网格轨道沿着行轴对齐方式;justify-content指定网格轨道沿着列轴对齐方式。它们支持下面属性:

  • normal
  • start
  • end
  • center
  • stretch
  • space-around
  • space-between
  • space-evenly
  • baseline
  • first baseline
  • last baseline

.grid {
    width: 100%;
    height: 300px;
    grid-template-columns: repeat(4, 45px);
    grid-template-rows: repeat(4, 45px);
    grid-gap: 0.5em;
    justify-content: start;
}

start指定列沿着行轴开始排列,它是justify-content默认值。

justify-content: end;

列沿着行末端开始排列。

justify-content: center;

列沿着行中间排列。

justify-content: space-around;

网格容器剩余列空间分配给每列的两端(相邻两列之间的间距是第一列与容器最左侧边缘或最后一列与容器最右侧边缘间距的两倍)。

justify-content: space-between;

网格容器剩余列空间平均分配给相邻的两列(第一列与容器最左侧边缘和最后一列与容器最右侧边缘没有任何间距)。

justify-content: space-evenly;

网格容器剩余列空间平均分配给列之间,相邻两列之间的间距与第一列和容器最左侧边级和最后一列与容器最右侧边缘间距相同。

align-content: start;

start允许网格网从网格容器列轴的开始位置排列,其是align-content的默认值。

align-content: end;

网格行在网格容器列轴末端。

align-content: center;

网格行在网格列中间。

align-content: space-around;

网格剩余行空间分配给每行之间上下,其中相邻两行的间距是第一行距离网格容器行顶端或者最后一行距离网格容器行末端之间间距的两倍。

align-content: space-between;

网格剩余行空间平均分配给相邻两行之间,其中第一行紧靠网格容器行的顶端,最后一行紧靠网格容器行的末端。

align-content: space-evenly;

网格剩余行空间平均分配给行之间,其中相邻两行的间距与第一行距容器行顶端间距和最后一行距容器末端的间距相等。

总结

这篇文章全面的介绍网格,就算不是一份完整的技术文档,也算是最全面、最简单介绍CSS Grid的一篇文章。而且都要比Mozilla的开发文档W3C规范还要简单明了。

这里有一些CSS Grid的资料源:

同时,在W3cplus.com上提供最全面的有关于CSS Grid的中文教程

最后,CSS Grid规范文档还在不断的完善,而且我也是个容易犯错的人,如果文章中有何不对之处,可以在下面的评论中指正。当然,如果你有更好的有关于CSS Grid文档,欢迎在下面的评论中与我们一起分享。

本文根据@jonsuh的《Learn CSS Grid》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://learncssgrid.com/

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/css/learncssgrid.htmlAir Jordan Trainer Essential