[译] 理解 CSS 网格布局:网格区域

原文连接:Understanding CSS Grid: Grid Template Areas,by Rachel Andrewjavascript

本文是讲解网格布局系列的第三篇,教你从网格布局新手到专家。css

咱们已经学了如何使用行号和命名网格线定位网格项目。其实还有一种定位网格项目的方式,它是对布局的天然描述——grid-template-areas 属性。本篇文章介绍如何使用 grid-template-areas 属性,以及它的工做原理。html

使用 grid-template-areas 描述布局

grid-template-areas 属性接收由一个或多个字符串组成的值。每一个字符串(包围在引号中)表明网格里的一行。它能够在已经设置了 grid-template-columns 属性(grid-template-rows  有无设置皆可)的网格上使用。java

下例中的网格,用了四个区域描述,每一个区域占据两行两列。网格区域是经过在多个单元格重复某个区域名称来划定范围的。bash

grid-template-areas: "one one two two"
                     "one one two two"
                     "three three four four"
                     "three three four four";
复制代码

在网格项目上使用 grid-area 属性,为其指定某个区域名称,即表示这个区域被该项目占据了。假设,有一个 .test 项目想要占据叫 one 的这个区域,能够这样指定:app

.test {
  grid-area: one;
}
复制代码

下面是一个完整的例子:ide

<div class="grid">
  <div class="one">1</div>
  <div class="two">2</div>
  <div class="three">3</div>
  <div class="four">4</div>
</div>

<style> .grid { display: grid; grid-template-areas: "one one two two" "one one two two" "three three four four" "three three four four"; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 100px); } .one { grid-area: one; } .two { grid-area: two; } .three { grid-area: three; } .four { grid-area: four; } </style>
复制代码

效果(demo):布局

image.png

若是使用 Firefox Grid Inspector 查看区域名称和行号分布,会看见每一个项目但都占据了两行两列,在网格中获得定位。post

image.png

使用 grid-template-areas 的规则

使用 grid-template-areas 属性有一些限定规则,若是打破规则,布局也就无效了。第一个规则是 你必需要完整描述网格,即要考虑网格里的每一个单元格。ui

若是某个单元格须要留空,就必须插入一个或多个点(好比 .... 等均可以)占位。注意在使用多个点时,点与点之间是没有空格的。

因此,还能够这样定义:

grid-template-areas: "one one two two"
                     "one one two two"
                     ". . four four"
                     "three three four four";
复制代码

效果(demo):

image.png

一个区域名不能在不连续的两块区域上使用。好比,下面的定义 three 的方式就是无效的:

grid-template-areas: "one one three three"
                     "one one two two"
                     "three three four four"
                     "three three four four";
复制代码

另外,不能建立一个非矩形区域。好比,“L”或“T”形区域的定义是无效的。

grid-template-areas: "one one two two"
                     "one one one one"
                     "three three four four"
                     "three three four four";
复制代码

格式化字符串

我喜欢用上面的方式来定义 grid-template-areas 属性——每一行字符串对应网格里的一行,看起来很直观。

有时为了达到列与列之间的对齐效果,我会选择使用多个点来指定空单元格。

grid-template-areas: "one   one   two  two"
                     "one   one   two  two"
                     "..... ..... four four"
                     "three three four four";
复制代码

固然,字符串排列在一行也是有效的:

grid-template-areas: "one one two two" "one one two two" "three three four four" "three three four four";
复制代码

grid-template-areas 和 grid-area

之因此每块命名区域都要保持为矩形,是由于每块区域都要求能用基于网格线方式实现——而使用四根网格线定义的区域必然是个矩形,不会是个非矩形。

我先举一个使用网格线定位项目的例子:

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

<style> .grid { display: grid; grid-template-columns: repeat(5, 100px); grid-template-rows: repeat(5, 50px); } .item { grid-column: 2 / 4; grid-row: 1 / 4; } </style>
复制代码

效果(demo):

image.png

就是说,只要为一个项目指定了下面四个属性就能准肯定位它在网格中的位置了:

  • grid-row-start
  • grid-column-start
  • grid-row-end
  • grid-column-end

grid-area 属性刚好支持以这种顺序指定项目位置的语法:

grid-area: grid-row-start grid-column-start grid-row-end grid-column-end
复制代码

所以,下面的写法:

.grid {
  grid-template-areas: "one   one   two  two"
                       "one   one   two  two"
                       "three three four four";
                       "three three four four";
}

.one {
  grid-area: one;
}

.two {
  grid-area: two;
}

.three {
  grid-area: three;
}

.four {
  grid-area: four;
}
复制代码

能够改写成:

.one {
  grid-area: 1 / 1 / 3 / 3;
}

.two {
  grid-area: 1 / 3 / 3 / 5;
}

.three {
  grid-area: 3 / 1 / 5 / 3;
}

.four {
  grid-area: 3 / 3 / 5 / 5;
}
复制代码

grid-area 有趣的地方在于还可以使用行号和命名网格线的方式,为项目指定定位区域。

使用行号的 grid-area

上面讲的是使用 4 个行号来指定 grid-area 属性。可是,若是不是 4 个呢?——好比,我只指定了前三个,没有指定第 4 个值——这时,会使用缺省值 auto,也就是默认延伸一个轨道。所以,若是为一个项目使用的是 grid-row-start: 3,就是说其余三个值都设置成 auto 了——此时项目默认占据一行一列:

.item { grid-area: 3; }
复制代码

效果:

image.png

使用 indent 的 grid-area

“indent”是对网格中 命名区域 的称呼。

下面我举了一个使用命名网格线指定 grid-area 属性的例子。

.grid {
  display: grid;
  grid-template-columns:
      [one-start three-start] 1fr 1fr
      [one-end three-end two-start four-start] 1fr 1fr [two-end four-end];
  grid-template-rows:
    [one-start two-start] 100px 100px
    [one-end two-end three-start four-start] 100px 100px [three-end four-end];;
}

.two {
  grid-area: two-start / two-start / two-end;
}
复制代码

注意到,这里我并未指定 grid-column-end 这个值。规范提到,在这种状况下,grid-column-end 的值就复制 grid-column-start 的,而在 grid-column-endgrid-column-start 同样的状况下,grid-column-end 值又会被丢弃,最后的结果与设置行号时同样了——等同于设置了 auto——自动延伸一个轨道。

还有,若是缺失的是第三个属性 grid-row-end 的值,它也是先复制 grid-row-start 的值,最后等同于设置 auto

下面举了一个比较全面的例子,列出了全部的状况:

<div class="grid">
  <div class="one">1</div>
  <div class="two">2</div>
  <div class="three">3</div>
  <div class="four">4</div>
</div>

<style> .grid { display: grid; grid-template-columns: [one-start three-start] 1fr 1fr [one-end three-end two-start four-start] 1fr 1fr [two-end four-end]; grid-template-rows: [one-start two-start] 100px 100px [one-end two-end three-start four-start] 100px 100px [three-end four-end]; } .one { grid-area: one-start / one-start / one-end / one-end; } .two { grid-area: two-start / two-start / two-end; } .three { grid-area: three-start / three-start; } .four { grid-area: four-start; } </style>
复制代码

效果(demo):

image.png

这也能解释了为何再给 grid-area 仅设置一个 ident 值的状况下也能正常工做的原理(实际拓展成 4 个值的写法了)。

还有一点你们须要知道的是,使用 grid-template-areas 属性建立命名区域的时候,每块区域的边缘网格线均可以使用区域名称引用。我以一个叫 one 的区域名称举例。

下面的写法,

.one {
  grid-area: one;
}
复制代码

等同于这种(其余三个值复制第一个值):

.one {
  grid-row-start: one;
  grid-row-end: one;
  grid-column-start: one;
  grid-row-end: one;
}
复制代码

若是是 -start 属性,那么 one 会被解析到这块区域行、列的起始线;若是是 -end 属性,那么 one 就会解析到这块区域行、列的终止线。固然,这种状况仅适应于 grid-area 使用一个命名区域值指定的场景。

在使用 grid-template-areas 的布局中层叠项目

使用 grid-template-areas 定义区域的时候,每一个单元格能且只能对应一个名称。固然,在完成主体布局以后,你仍然可使用行号向布局中叠加新的项目。

下例中,在主题布局以外,我基于网格线在布局中叠加了一个项目:

<div class="grid">
  <div class="one">1</div>
  <div class="two">2</div>
  <div class="three">3</div>
  <div class="four">4</div>
  <div class="five">5</div>
</div>

<style>
.grid {
  display: grid;
  grid-template-areas:
    "one one two two"
    "one one two two"
    "three three four four"
    "three three four four";
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 100px);
}

.one {
  grid-area: one;
}

.two {
  grid-area: two;
}

.three {
  grid-area: three;
}

.four {
  grid-area: four;
}

/* 与前面不一样的是,这个项目是使用行号定位的 */
.five {
  grid-row: 2 / 4;
  grid-column: 2 / 4;
}
</style>
复制代码

效果(demo):

image.png

你还可使用命名网格线来指定项目占据的行和列。更好的是,在使用 grid-template-areas 定义网格区域的时候,实际上也会同时给区域周围的四根网格线生成一个以区域名为前缀的名字,区域起始边缘的网格线的名称是 xx-start 的形式,终止边缘的的网格线的名称则是 xx-end 的形式。

以命名区域 one 为例,它的起始边线名字叫 one-start,终止边线的名字则叫 one-end

网格中,你可使用这些隐式生成的命名网格线定位项目。这在须要不一样的断点处从新定义网格布局的场景中,你但愿某个定位项目始终位于某个行名以后,会颇有用。

<div class="grid">
  <div class="one">1</div>
  <div class="two">2</div>
  <div class="three">3</div>
  <div class="four">4</div>
  <div class="five">5</div>
</div>

<style> .grid { display: grid; grid-template-areas: "one one two two" "one one two two" "three three four four" "three three four four"; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 100px); } .one { grid-area: one; } .two { grid-area: two; } .three { grid-area: three; } .four { grid-area: four; } .five { grid-row: one-start / three-end; grid-column: three-start / four-start; } </style>
复制代码

效果(demo):

image.png

在响应式设计中使用 grid-template-areas

我在构建组件库的时候,发使用 grid-template-areas 属性能够很准确的从 CSS 里看到组件组成方式。特别是在不一样断点处从新定义网格布局的时候,我只要给 grid-template-areas 属性从新赋值,就能改变当前网格里轨道数量和区域分布。

在下面的 CSS 中,默认组件是单列布局的,在视口宽度达到 600px 以上时,我会从新给 grid-template-area 属性赋值,改变成两列布局。这种方法的好处(也是我前面说过的)就是任何看到这段 CSS 的人均可很清晰看懂是如何布局的。

.wrapper {
  background-color: #fff;
  padding: 1em;
  display: grid;
  gap: 20px;
  grid-template-areas:
    "hd"
    "bd"
    "sd"
    "ft";

}

@media (min-width: 600px) {
  .wrapper {
    grid-template-columns: 3fr 1fr;
    grid-template-areas:
      "hd hd"
      "bd sd"
      "ft ft";
  }
}

header { grid-area: hd; }
article {grid-area: bd; }
aside { grid-area: sd; }
footer { grid-area: ft; }
复制代码

可访问性

使用 grid-template-areas 和 grid-area 属性定义布局的方式,可能会带来的一个问题就是 元素的视觉呈现跟在源码的顺序多是不一致的。若是是使用 Tab 按键或语言助手访问的页面,那么看到或听到的内容是按照源码顺序来的,若是布局里的元素由于诗视觉须要移动了位置,那么就会致使视觉呈现上的混乱。因此,在移动项目的时候,必定要留意视觉呈现与源码上的关联性,不至于使用辅助设备访问时,获得不一致的体验。

总结

以上是使用 grid-template-areagrid-area 属性建立布局的所有内容。 若是你还没使用过这种布局方式的话,能够尝试一下。我发现使用这种布局方式设计原型页面很是方便。

(正文完)


广告时间(长期有效)

我有一位好朋友开了一间猫舍,在此帮她宣传一下。如今猫舍里养的都是布偶猫。若是你也是个爱猫人士而且有须要的话,不妨扫一扫她的【闲鱼】二维码。不买也没关系,看看也行。

(完)

相关文章
相关标签/搜索