原文连接:Understanding CSS Grid: Grid Lines,by Rachel Andrewcss
本文是讲解网格布局系列的第二篇,教你从网格布局新手到专家。html
本系列第一篇讲到如何建立网格容器,以及在容器元素上可以使用的属性。网格格式化上下文一旦建立,你也就有了网格线了。有了网格线,你就能在网格项目上添加属性,对项目作定位(place items)了。算法
读完本篇文章,你将学到:跨域
grid-column-start
、grid-column-end
、grid-row-start
、grid-row-end
以及对应的简写属性 grid-column
和 grid-row
。grid-area
属性。在网格中定位一个项目时,须要先设置它从哪根线开始,到哪儿根线结束。举个例子,我要在一个 5x5 的网格中定位一个项目,让它占据第二列和第三列,第一行到第三行。我会使用下面的 CSS 代码(注意,这里使用的是网格线,而非网格轨道)。函数
.item {
grid-column-start: 2;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 4;
}
复制代码
上面的代码还能够简写为如下形式:斜线以前表示起始线(start line),斜线以后表示终止线(end line)。布局
.item {
grid-column: 2 / 4;
grid-row: 1 / 4;
}
复制代码
效果(demo):
post
注意,虽然 .item
的内容不多,但仍是占满了整个定位区域。这是由于项目上的对齐属性 align-self
和 justify-self
的默认值为 stretch
。网站
若是项目只需跨越一个轨道,那么能够忽略设置终止线,由于项目默认就跨域一个轨道。举个例子,设置一个只占据第二列的项目。以前会这么写:ui
.item {
grid-column: 2 / 3;
}
复制代码
其实能够简写成这样的:spa
.item {
grid-column: 2;
}
复制代码
grid-area
属性定位咱们还能用 grid-area
属性定位项目。下一篇文章会全面讲它的用法,不过如今咱们只讲使用行号来设置它的方式:
.item {
grid-area: 1 / 2 / 4 / 4;
}
复制代码
grid-area
属性行号的设置顺序是这样的:grid-row-start
、grid-column-start
、grid-row-end
、grid-column-end
。若是你是在水平、从左到右的语言环境下开发的(好比英语),那么这几个分别对应的方向是 top
、left
、bottom
和 right
——跟设置 margin
的方向是相反的——逆时针。
这种设置网格线的方式是为了能适配不一样的书写模式(下面会介绍)——先设置起始端,在设置结束端,这与表明物理方向的 top
、left
... 是不一样的。固然,上面这种设置项目位置的方式我不会用,仍是会使用 grid-column
和 grid-row
这两个简写属性,由于它们的可读性更高。
在一个网格容器中,使用 grid-template-columns
或 grid-template-rows
设置的那部分网格区域称为 显式网格。在定义显式区域的同时,还会定义网格线。
这些网格线会编号,起始值是 1
,在行内和块方向两个维度上编号。对水平书写模式、从左向右排版的语言来讲:行内方向(inline direction)的编号从左开始;块方向(block direction)的编号则从上面开始。
这里的“行内方向”和“块方向”的概念须要介绍一下:
咱们平时在开发网站时,所浏览中、英文网页文本排版方式,基本都是从左到右、从上到下的。咱们把> 文字书写方向就叫作行内方向(inline direction),文字折行方向叫作块方向(block direction)。
一样的,若是是垂直书写语言——像中国古籍里排版方式——那么从上到下就是指行内方向,从右到左是块方向。
若是是在水平 RTL(right to left)语言环境下,好比阿拉伯语。此时,块方向仍然从上面开始编号,但行内方向编号就是从右开始的了。
writing-mode: vertical-rl
。那么块方向则是从右面开始编号的,行内方向则从上面开始编号。
另外,显式网格的最后一根网格线可使用数值 -1
指代,同理倒数第二第三跟网格线分别是 -2
、-3
,依次类推。假设·,如今有一个项目从网格的第一列横跨到最后一列,那么能够这样写:
.item {
grid-column: 1 / -1;
}
复制代码
隐形网格的网格线也是从 1
开始编号的。假设我建立一个网格,只显式指定了列(使用 grid-template-columns 属性),并未显式指定行,只使用 grid-auto-rows: 5em
指定了隐式行的尺寸。
在下面的网格布局中,我为一个项目添加了 .placed
类,指定它从第一行跨越到最后一行。
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div class="placed">Placed</div>
</div>
<style> .grid { display: grid; grid-template-columns: repeat(5, 100px); grid-auto-rows: 5em; } .grid > .placed { background-color: orange; grid-row: 1 / -1; /* the end line is in the implicit grid so -1 does not resolve to it*/ } </style>
复制代码
咱们来看看结果(demo):
.placed
的定位结果与咱们想象的有出入,按道理应该占两行才对,实际只占了一行。这是由于如今的行轨道没有使用 grid-template-rows
显式建立,致使行号 -1
被解析为 2
,而非 3
。
如今尚未办法定位到隐式网格中的最后一根网格线,由于并不知道一共有多根网格线。
除了使用行号定位项目,咱们还你能使用命名网格线来定位项目。一条网格线能够取多个名字,名字包围在方括号 []
中,网格线名称在各轨道尺寸(tracks sizes)之间定义的。
.grid {
display: grid;
grid-template-columns: [full-start] 1fr [main-start] 2fr 2fr [main-end full-end];
}
复制代码
有了命名网格线,就能够用它来替换默认行号来定位项目。
.item {
grid-column: main-start / main-end;
}
复制代码
效果(demo):
若是一根网格线定义了多个名字,那么你能够任选其一使用。这么多名称最终都是指代同一根网格线。
这是一个颇有趣的场景,多个网格线使用了同一个名字。这会发生在使用了 repeat()
函数的地方。下面例子中,我定义了一个八列网格,是经过 repeat(4, [sm] 1fr [lg] 2fr)
重复四次获得结果。还将较小轨道尺寸左边的网格线命名为 sm
,较大轨道尺寸左边的网格线则命名为 lg
。
这时,若是要指定是具体哪根网格线的时候,就要用到索引了。好比,我想把一个项目从第二根 sm
网格线延伸到第三根 lg
网格线,我会使用 grid-column: sm 2 / lg 3
。另外,若是没给网格线指定索引的状况下,默认将解析到第一根叫这个名字的网格线。
<div class="grid">
<div class="item">Item</div>
</div>
<style> .grid { display: grid; grid-template-columns: repeat(4, [sm] 1fr [lg] 2fr); grid-template-rows: repeat(5, 50px); } .item { grid-column: sm 2 / lg 3; grid-row: 1 / 4; } </style>
复制代码
效果(demo):
span
有些状况,只须要一个项目跨越必定数量的轨道,但不知道确切的网格位置。好比,当使用自动定位算法(auto-placement)定位项目的时候,只知道它们跨越了多个轨道,而非默认的就跨越一个。这个时候,就要使用关键字 span
了。
下面举了一个例子, .item1
设置了 grid-column: auto / span 3
:
<div class="grid">
<div class="item1">Item 1</div>
<div class="item2">Item 2</div>
</div>
<style> .grid { display: grid; grid-template-columns: repeat(6, 1fr); grid-template-rows: repeat(5, 50px); } .item1 { grid-column: auto / span 3; } .item2 { grid-column: auto / span 2; grid-row: auto / span 2; } </style>
复制代码
来看看效果(demo):
未来 grid-template-columns
和 grid-template-rows
属性开始全面支持 subgrid
值以后,这种技术将变得很是有用。好比,在卡片布局中,每一个卡片包含一个标题和内容区域,咱们但愿这些卡片里的内容也是彼此对齐的,那么能够经过为卡片设置 grid-template-rows
设置为 subgrid
来控制卡片从父网格中继承(两)行,这样就能实现卡片内容的自动对齐效果了。
<div class="grid">
<article class="card">
<h2>This is the heading</h2>
<p>This is the body of the card.</p>
</article>
<article class="card">
<h2>This is the heading and some headings are bigger</h2>
<p>This is the body of the card.</p>
</article>
<!-- ... -->
</div>
<style> .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); } /* * 1. `.card` 既是一个网格项目(隶属于 `.grid`),也是一个网格容器。 * 2. `.card` 做为网格项目占据两行轨道,它在行上的行为表现会传递给做为容器的它的子项目。 * / .card { grid-row: auto / span 2; /* 2 */ display: grid; /* 1 */ grid-template-rows: subgrid; /* 2 */ } </style>
复制代码
看下效果(demo。在 Firfox 中查看,Chrome 中目前不支持 subgrid
值):
网格系统会自动将项目定位到网格上的空单元格中,而不会遇到项目被定位到同一个单元格中的状况。可是能够基于网格行号、将不一样的项目放入同一网格单元中。下例中,我设置了一个跨越两行轨道的图片,还有一个位于第二行轨道的有半透明背景效果的标题文本。
<div class="grid">
<figure>
<img src="https://images.unsplash.com/photo-1576451930877-c838b861e9b6?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ" alt="lights">
<figcaption>This is the caption</figcaption>
</figure>
<!-- ... -->
</div>
<style> .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } figure { display: grid; grid-template-rows: 300px min-content; } figure img { object-fit: cover; width: 100%; height: 100%; grid-row: 1 / 3; grid-column: 1; } figcaption { grid-row: 2; grid-column: 1; background-color: rgba(0,0,0,.5); color: #fff; padding: 10px; } </style>
复制代码
效果(demo):
这些项目将按照它们在 HTML 中出现的顺序排列。上例中,标题处于图片以后,所以会显示在图片上面。若是标题在前面,那么它就会挡在图片后面,咱们就看不见了。另外,若是标题必须在图片前面,那么你能够经过使用 z-index
属性来控制层叠顺序,让图片显示。
若是你混合使用网格线定位与自动定位,须要多加当心。当项目是根据自动定位算法定位的时候,会依次将本身定位到网格上、下一个可用的空白空间。
<div class="grid">
<figure>...</figure>
<figure>...</figure>
<figure>...</figure>
<!-- ... -->
</div>
<style> .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); } figure { margin: 0; display: grid; grid-template-rows: 200px min-content; } figure:nth-child(odd) { grid-column: auto / span 2; } figure:nth-child(2) { grid-column: auto / span 3; } </style>
复制代码
效果(demo):
网格默认的定位行为是这样的:若是当前剩余的空白空间不足以放得下项目,那么就换行显示,这样就会致使上一行会留下空白。你能够经过设置 grid-auto-flow
值为 dense
(该单词为“密集”的意思,意思即尽量密集的排列项目)来控制这种行为。在这种状况下,若是当前剩下的空白区域足以放得下后续的某个项目,那么这个后续项目会自动挤上来显示,这会致使显示顺序与源码顺序不一致。咱们对上例稍做修改,添加一个grid-auto-flow: dense
设置。结果发现项目 3 放在项目 2 以前显示了。
.grid {
/* ... */
grid-auto-flow: dense; /* 增长了这一句 */
}
复制代码
效果(demo):
请注意,此行为可能会致使用户使用 Tab 键浏览文档时出现问题,由于视顺序与源码顺序不一样。自动定位算法会寻找第一个可用的间隙来排布网格项目。打个比方:布局时把头几个网格项目避开顶部区域,留下空白,那么自动定位算法会将后续合适尺寸的项目安排到这些轨道中。
我这里再举一个例子(也是本篇最后一个例子):咱们基于行号定位(第 1 项和第 2 项)将第一行的空间空了下来,随后会看到后来的项目会向上移动来填补这些空白空间。
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
figure:nth-child(odd) {
grid-column: auto / span 2;
}
figure:nth-child(1) {
grid-row: 2;
grid-column: 1;
}
figure:nth-child(2) {
grid-row: 2;
grid-column: 2 / -1;
}
复制代码
效果(demo):
看到没?第1、第二个项目被定位到第二行显示了,空下来了第一行,这时后续的第3、第四个项目被自动定位算法推到了第一行。
注意,在动图的最后我还作了一件事情,就是在网格容器上设置了 grid-auto-flow: dense
,致使第六个项目位置上移了。这是为了让你们区分自动定位与密集定位:
自动定位算法很是值得咱们理解的。这对于理解某些场景下的布局表现会有帮助——好比,若是在网格中新增长了一个项目但没有设置定位区域,则它可能不会像咱们所想的那样排在网格的最后面,而是出如今比较靠前的某个“奇怪”位置。
关于网格线的内容仍是挺多的。须要记住的是,网格行号从网格建立出来的那一刻起就随之产生,你能够经过指定初始行号和结束行号来定位一个项目。在下一篇文章,我还会介绍另外一个定位网格项目的形式:grid-template-areas
。
(正文完)
广告时间(长期有效)
我有一位好朋友开了一间猫舍,在此帮她宣传一下。如今猫舍里养的都是布偶猫。若是你也是个爱猫人士而且有须要的话,不妨扫一扫她的【闲鱼】二维码。不买也没关系,看看也行。
(完)