css网格布局:建立网格容器

原文做者:Rachel Andrew
原文连接:www.smashingmagazine.com/2020/01/und…css

译者注: CSS Grid布局 (又名"网格"),是一个基于二维网格布局的系统,旨在改变咱们基于网格设计的用户界面方式。咱们经常使用的Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,能够看做是一维布局,并不适用于复杂的二维布局。网格(Grid)是第一个专门为解决布局问题而建立的CSS模块,用来解决咱们以前在制做网站时使用各类复杂处理的布局问题。html

在进入正文以前为了防止翻译上存在一些歧义或者不许确的地方,你们先了解几个关于网格布局的关键术语。前端

  • container:容器,就是采用网格布局的区域
  • row line: 行线,容器里面的水平区域称为"行"(row)
  • column line: 列线,垂直区域称为"列"
  • track: 网格轨道,是两条网格线之间的空间,即行线和行线,或列线和列线之间所造成的区域,用来摆放子元素
  • gap: 网格间距,行线和行线,或列线和列线之间所造成的不可利用的区域,用来分隔元素
  • cell: 网格单元格,由行线和列线所分隔出来的区域,用来摆放子元素
  • area: 网格区域,由单个或多个网格单元格组成,用来摆放子元素
  • grid line: 网格线,划分网格的线,水平网格线划分出行,垂直网格线划分出列

好了,下面正式开始:

概要:在一个新的系列中,Rachel Andrew将会向咱们介绍css网格的规范。在本次文章中,咱们将会详细了解当咱们建立了一个网格容器的时候会发生什么,以及各类各样能够应用在网格容器上的属性。浏览器

这是Smashing Magazine上面关于网格布局系列文章的开篇。尽管网格布局在2017年浏览器就已经支持使用了,可是不少开发者仍是没有机会在项目中使用它。彷佛有不少新的属性和值与CSS网格布局相关。这使得它势不可挡。然而,它的不少规范细节均可以使用不一样的方式来实现,这意味着你在没有彻底了解规范的状况下,也能够开始使用。本系列旨在将您从网格布局的新手带到专家:一路上有不少实用的使用技巧交给你们。ide

开篇的文章将会包括:你在建立一个网格容器时将会发生什么,以及各类你能够应用在父元素上的属性以控制网格。您将发现,有几个用例仅在将属性应用在网格容器上时才会生效。 这篇文章中,咱们包括:svg

  • 使用display: grid或者display: inline-grid建立网格容器
  • 使用grid-template-columns 和 grid-template-rows属性设置列和行
  • 使用grid-auto-columns 和 grid-auto-rows控制内含尺寸

建立一个网格容器

grid就像flex布局同样,是一种display属性。因此使用display: grid来告诉浏览器你想使用网格布局。以后,设置了网格属性的元素将成为一个块级元素,它里面全部的直接子元素都将处于一个网格格式上下文中。这就代表,它们都将表现出网格元素的性质,而不是普通的块级或者行内元素。函数

也许,你尚未在你的页面上看到差异。那是由于你尚未建立一个行或者列。尽管已经默认建立了一个行,并包含你全部的子元素。这些子元素在一列中上下排布。表现出的行为看起来就像块级元素。布局

若是有任何文本字符串(未包装在元素中)便是网格容器的直接子级,你就会看到不一样,由于字符串将包装在匿名元素中并成为网格项。任何行内元素,好比span,只要直接处于网格容器中,就会表现出网格项的属性。flex

下面的示例有两个块级元素,在字符串中添加一个包含在span中的文字字符串。咱们最终获得5个网格项:网站

  • 两个div元素
  • span前面的文本字符串
  • span
  • span以后的文本字符串
// html
<div class="grid">
  <div>Item one</div>
  <div>Item Two</div>
  A string of text with a <span>span element</span> in the middle.
</div>
This string of text follows the grid.
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

最后的表现:

若是使用Firefox的grid Inspector检查网格,能够看到为为每一个网格项建立的5行轨迹。

Grid Inspector能够帮助你查看建立了多少row元素
你也能够经过display: inline-grid建立一个行内网格。在这个例子中,你的网格变成了一个行级盒子。可是,直接子项仍然是网格项,其行为方式与块级框中的网格项相同(它只是外部显示类型)。这就是为何当网格容器与页面上的其余框并排时,它的行为与上面的相同。

下一个示例有一个网格,后面跟着一个文本字符串,由于这是一个内联级别的网格,文本能够与它一块儿显示。内联级别的内容不会像块级别的内容那样拉伸以占用内联维度中的全部空间。

<div class="grid">
  <div>Item one</div>
  <div>Item Two</div>
  A string of text with a <span>span element</span> in the middle.
</div>
This string of text follows the grid.
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: inline-grid;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

最后的表现:

列和行

为了使布局看起来像网格,你须要添加行和列。咱们使用grid-template-columns 和 grid-template-rows属性来建立。在规范中有一个定义叫作网格轨道track-list

这些属性指定了行的名字以及网格的追踪尺寸函数。网格模板列属性grid-template-columns指定网格列的尺寸跟踪方法,而网格模板行grid-template-rows指定网格行的跟踪函数。

下面列出了一部分有效影响轨道尺寸的值:

属性 做用
grid-template-columns: 100px 100px 200px; 建立三列网格:第一列是100px,第二列是100px,第三列是200px
grid-template-columns: min-content max-content fit-content(10em) 建立三列网格:第一列追踪min-content尺寸,第二列是max-content,若是容器大小超过10em,第三列也是max-content,不然就撑到10em
grid-template-columns: 1fr 1fr 1fr; 使用fr建立了三列网格,这三列将平分容器尺寸
grid-template-columns: repeat(2, 10em 1fr); 使用重复命令建立了尺寸分别为10em 1fr 10em 1fr 的四列网格
grid-template-columns: repeat(auto-fill, 200px); 建立尽量多的宽为200px的列,若是剩余控件不足200px,就留下空白
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); 建立尽量多的宽为200px的列,若是剩余控件不足200px,已建立的列将平均分配剩余空间。
grid-template-columns: [full-start] 1fr [content-start] 3fr [content-end] 1fr [full-end]; 建立三列网格:第一列和第三列各有一份可用空间,而中间列占三份。将行名称放在方括号中对行进行命名。

如您所见,有不少方法能够建立网格轨道(track list)!让咱们来看看这些都是如何工做的,并给出一些提示,说明为何要使用每这些属性。

使用长度单位

你可使用任何长度单位或者百分比建立你的网格轨道(tracks)。若是网格轨道(tracks)的大小加起来小于网格容器中可用的大小,则默认状况下,网格轨道(tracks)将会从左到右排列,剩余部分就会空白。这是由于align-content 和 justify-content这两个属性的默认值是start。你可使用校准元素将元素分隔开或者移动到容器最后面。详细的介绍能够看个人这篇文章“How To Align Things In CSS”.

<div class="grid">
  <div>Item One</div>
  <div>Item Two</div>
  <div>Item Three</div>
  <div>Item Four</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 100px 200px 100px;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

你也可使用min-content, max-content 和 fit-content()属性。使用min-content属性,会建立尽量小的网格轨道(tracks)来避免出现溢出的状况。因此,看成为列的属性时,会尽量的折叠里面的内容。这时网格轨道(track)的高度就变成了容器中最长单词或最大固定大小元素的大小。

使用max-content属性不会引发任何折行。在一列中,文本字符不会折行,这可能会引发溢出。

fit-content是css函数,只能经过传值来使用。这个值就是网格轨道所能增加到的最大值。它的表现就像max-content同样,会随着内容的不断变长而变宽。可是当内容长度超过这个值之后,里面的元素就开始折行。因此,这个网格轨道有可能小于你所传的值,但不会比它大。

<div class="grid">
  <div>Item One</div>
  <div>Item Two Item Two</div>
  <div>Item Three Item Three Item Three</div>
  <div>Item Four</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: min-content max-content fit-content(10em);
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果

你能够在个人这篇文章 How Big Is That Box? Understanding Sizing In CSS Layout中发现更多关于网格尺寸和布局的方法。

若是你的tracks占用的空间超过你的容器,它们就会溢出。若是你使用百分比,就与基于百分比的浮动或弹性布局同样,若是想要避免溢出,就要注意总和不要超过100%。

fr 单位

网格布局包括一种方法可让你避免本身计算百分比-就是使用fr。它并非一个值,因此不能和calc()一块儿使用。它是一个弹性单位,表示网格中的可用空间。

这就表示,当咱们1fr 1fr 1fr;设置时,剩余空间会被分红三分并平分空间。当使用2fr 1fr 1fr,空间会被分红四分,其中两份被分配给第一个网格轨道,剩下两个网格轨道分别占据一份。

<div class="grid">
  <div>Item One</div>
  <div>Item Two Item Two</div>
  <div>Item Three Item Three Item Three</div>
  <div>Item Four</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

最终渲染:

须要注意的是,默认状况下共享的是可用空间,而不是容器中的总空间。若是你的任意一个网格轨道中包含规定尺寸的元素或者一个没法被折行的文本,它会在空间被分配以前布局。
在一下个例子中,我将去掉第三列中字符的字间距。这样就造成了一个长的不可折断的字符串,因此,在进行网格布局以前会优先处理字符串的布局,将它所在的列撑开了。而后剩余的两列按照2:1的比例进行布局。

<div class="grid">
  <div>Item One</div>
  <div>Item Two Item Two</div>
  <div>ItemThreeItemThreeItemThree</div>
  <div>Item Four</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

你能够将固定尺寸的网格轨道和fr一块儿使用。例如你能够建立一个容器,包含两个固定尺寸的列,两个列中间区域自适应。

<div class="grid">
  <div>Fixed</div>
  <div>Flexible</div>
  <div>Fixed</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: 100px 1fr 100px;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

另外,你也可使用fit-content(300px)建立第一列,剩余得部分用fr处理。这样容器的第一部分就会根据内容占据所须要的空间。fr单位的列会扩大占据剩余部分。 若是元素中的内容放入更大的内容(好比设置属性max-width: 100%的图片),第一列最大宽度只能到300px。fr单位的列占据剩余部分。 将fr和fit-content一块儿使用也是让你的网站更加灵活的一种方式。

<div class="grid">
  <div><svg width="24" height="24" viewBox="0 0 24 24">
  <path d="M23,12L20.56,9.22L20.9,5.54L17.29,4.72L15.4,1.54L12,3L8.6,1.54L6.71,4.72L3.1,5.53L3.44,9.21L1,12L3.44,14.78L3.1,18.47L6.71,19.29L8.6,22.47L12,21L15.4,22.46L17.29,19.28L20.9,18.46L20.56,14.78L23,12M13,17H11V15H13V17M13,13H11V7H13V13Z"></path>
</svg></div>
  <div>This side is flexible</div>
</div>

<div class="grid">
  <div><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/balloon-sq4.jpg" alt="balloons"></div>
  <div>This side is flexible</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  margin: 1em 0;
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: fit-content(300px) 1fr;
  width: 600px;
}

img {
  max-width: 100%;
  display: block;
}

复制代码

渲染结果:

REPEAT()方法

使用repeat()函数建立网格轨道能够很方便的建立重复属性的列,避免一遍又一遍的输入一样的值。好比,下面两列的做用是同样的。

grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(12, 1fr);
复制代码

repeat()函数的第一个参数是要建立的网格轨道个数,第二个参数为列的尺寸,用逗号隔开。

你也能够将repeat()做为一部分参数,下面的例子中,建立了一个1fr的列,三个宽为200px的列,最后一列为1fr。

grid-template-columns: 1fr repeat(3,200px) 1fr
复制代码

另外,函数传入一个值表示建立列的个数,但也可使用auto-fill or auto-fit。使用这两个关键词意味着建立列的个数并非固定的,而是根据容器的宽度,建立尽量多的列。

<div class="grid">
  <div>Item One</div>
  <div>Item Two</div>
  <div>Item Three</div>
  <div>Item Four</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fill, 200px);
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

若是建立列的宽度是固定的,那么除非容器正好能被列进行平分,不然就会留下空白部分。好比个人容器宽度为500px,就会建立两个200px的列和100px的空白。

针对上面的问题,可使用另一个网格函数定义最小值,剩余的空间能够被全部已建立的列进行平分。minmax()定义最小值和最大值。好比定义列最小为200px,最大为1 fr,那么就会建立尽量多的宽为200px的列来填充容器。由于最大值为1fr,因此若是有剩余空间,就会被已建立列平分。

<div class="grid">
  <div>Item One</div>
  <div>Item Two</div>
  <div>Item Three</div>
  <div>Item Four</div>
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

上面,我提到了两个关键词auto-fill and auto-fit。若是第一行有足够的内容去填充,那么他们的表现是同样的。可是若是没有(好比删除其它内容只剩下一列),那么它们的表现就会有所不一样。

使用auto-fill会保留剩余空间,尽管没有内容填充了。

<div class="grid">
  <div>Item One</div>

</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

可是auto-fit会将剩余空间折叠。

<div class="grid">
  <div>Item One</div>

</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}
复制代码

渲染结果:

经过Firefox Grid Inspector,能够看到,第二列仍然存在,只不过宽度变为了0。咱们能够看到第三条网格线,这说明容器中存在两条网格轨道。

命名行

我最后说一下行的命名。当使用网格的时候,你能够得到每行行数,如今你也能够给每一行命名。将行的名字放在中括号里。也能够为行定义多个名称,用空格分开。下面的例子中,每一个行我都定义了两个名字。

grid-template-columns: [main-start sidebar-start] 1fr [sidebar-end content-start] 4fr [content-end main-end]
复制代码

除了单词span,你能够为行定义任何您喜欢的名称,由于span是一个保留字,在网格上放置项目时使用它。
注意:本系列后续文章中,我将更多地讨论基于行的布局以及如何使用命名行。同时,个人这篇文章“Naming Things in CSS Grid Layout”以帮助你更好的理解这些。

显式vs隐式网格

当使用grid-template-columns 和 grid-template-rows属性定义时,你就是很明确的显式定义了网格。每个网格轨迹都是根据你的赋值建立的。
当你定义的轨道数量超过容器的空间,或者将一个单元放在建立的网格以外,将建立隐式网格轨道。这些隐式轨道默认自适应大小。好比,我在父元素上声明display:grid,它包含的每一项都会建立一个行轨道。尽管我并无去定义row,可是由于它们变成了网格布局中的元素,为了放置这些元素,就会自动建立出行轨道。

你可使用grid-auto-rows 或者 grid-auto-columns属性设置隐式行或者列的尺寸。若是你但愿全部的隐式列都至少有200px的宽,并随着内容的增大而增大,你能够这样设置:

grid-auto-rows: minmax(200px, auto)
复制代码

若是你但愿第一个隐式行自适应大小,第二行为min-content直到全部网格项都被容纳。你能够传多个值:

grid-auto-rows: auto 100px
复制代码
<div class="grid">
  <div>Item one</div>
  <div>Item Two</div>
  A string of text with a <span>span element</span> in the middle.
</div>
复制代码
body {
  padding: 50px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

.grid {
  border: 5px solid rgb(111,41,97);
  display: grid;
  grid-auto-rows: auto 100px;
  width: 500px;
}

.grid > * {
  background-color: rgba(111,41,97,.4);
  border-radius: 5px;
  padding: 10px;
}

复制代码

使用具备自动放置功能的网格

建立一个网格(并容许浏览器自动放置元素)可让您实现很是有价值的模式方面有很长的路要走。咱们尚未设计在网格上放置项目,可是许多状况下网格的布局不须要进行任何放置。容器的子元素只是简单地按照代码中的顺序自动放置在每个网格中。

若是你刚刚接触css网格,那么尝试使用不一样方式定义网格轨迹并查看元素是如何放置的,是一个很好的开始。

END

若是你们想要持续关注网格布局以及本系列翻译,能够关注公众号“前端记事本”,及时得到最新消息推送。

相关文章
相关标签/搜索