关于 CSS Grid 的一些有趣的事实

Avatar of Manuel Matuzovic
Manuel Matuzovic

DigitalOcean 为您旅程的各个阶段提供云产品。立即开始使用 $200 免费积分!

去年,我在完成一个研讨会后整理了一篇关于 CSS Grid 布局的有趣事实的文章 关于 CSS 网格布局的一些有趣的事实。今年,我参与了另一个研讨会,并且又学习了一些关于 我们都非常喜欢的布局规范 的激动人心的新事实。

当然,我不会把我的知识藏着掖着。我很乐意再次与您,CSS-Tricks 社区分享我的发现。

理解 `grid` 快捷方式的工作原理

有时候,阅读和理解网格规范(或实际上任何其他规范)的部分内容会非常困难。

例如,我花了相当长的时间才理解如何正确使用 `grid` 快捷方式。规范中指出有效值为

<‘grid-template’> | <‘grid-template-rows’> / [ auto-flow && dense? ] <‘grid-auto-columns’>? | [ auto-flow && dense? ] <‘grid-autwo-rows’>? / <‘grid-template-columns’>

如果您花时间或您习惯阅读规范,您可以理解它。我尝试了几种组合,但都失败了。最终帮助我的是规范中的一句话

请注意,您只能在一个网格声明中指定显式或隐式网格属性。

Rachel Andrew 有一系列文章,文章系列,以 CSS Grid 为例,帮助解释如何阅读规范。

因此,我们可以使用 `grid` 快捷方式指定大量内容,但不能一次性指定所有内容。以下是一些示例。

使用 `grid` 代替 `grid-template`

grid-template 属性是用于在单个声明中设置 `grid-template-columns`、`grid-template-rows` 和 `grid-template-areas` 的简写。我们可以用 `grid` 快捷方式做同样的事情,它更简洁一些。

grid: "one one" 200px 
      "two four" 
      "three four" 
      / 1fr 2fr;

/* shorthand for: */ 
/*
  grid-template-areas: "one one" "two four" "three four";
  grid-template-rows: 200px;
  grid-template-columns: 1fr 2fr;
*/

此快捷方式创建了三行两列,并有四个命名的网格区域。第一行的高度为 `200px`,而第二行和第三行的高度为 `auto`。第一列宽度为 `1fr`,第二列宽度为 `2fr`。

查看代码笔 网格快捷方式 - 区域、显式行和列,由 Manuel Matuzovic (@matuzo) 在 CodePen 上创建。

想了解更多关于显式网格和隐式网格的区别?查看 这篇我撰写关于该主题的文章,发布在 CSS-Tricks 上。

如果不需要,我们不必指定区域。我们可以仅使用 `grid` 快捷方式来定义显式行和列。以下两个代码片段本质上是做同样的事情

grid-template-rows: 100px 300px;
grid-template-columns: 3fr 1fr;
grid: 100px 300px / 3fr 1fr;

处理隐式行和列

可以使用 `grid` 快捷方式指定 `grid-auto-flow`,但它并不完全按照我们的预期工作。我们不能仅仅在声明中添加 `row` 或 `column` 关键字。相反,我们必须在斜杠的正确位置使用 `auto-flow` 关键字。

如果它位于斜杠左侧,则快捷方式将 `grid-auto-flow` 设置为 `row` 并创建显式列。

grid: auto-flow / 200px 1fr;

/* shorthand for: */ 
/*
  grid-auto-flow: row;
  grid-template-columns: 200px 1fr;
*/

如果它位于斜杠右侧,则快捷方式将 `grid-auto-flow` 设置为 `column` 并创建显式行。

grid: 100px 300px / auto-flow;

/* shorthand for: */ 
/*
  grid-template-rows: 100px 300px;
  grid-auto-flow: column;
*/

我们还可以与 `auto-flow` 关键字一起设置隐式轨道的大小,这分别将 `grid-auto-rows` 或 `grid-auto-columns` 设置为指定的值。

grid: 100px 300px / auto-flow 200px;

/* shorthand for: */ 
/*
  grid-template-rows: 100px 300px;
  grid-auto-flow: column;
  grid-auto-columns: 200px;
*/

查看代码笔 网格快捷方式 - 显式行和隐式列,由 Manuel Matuzovic (@matuzo) 在 CodePen 上创建。

Edge 中的特性查询

使用 特性查询 检查 CSS Grid 的支持效果很好,因为所有支持 Grid 的浏览器也都理解特性查询。这意味着我们可以检查浏览器是否支持旧规范或新规范,或者两者都支持。两者都支持?从 Edge 16 开始,Edge 不仅支持新规范,还支持旧规范。

因此,如果您想区分支持新规范的 Edge 版本和不支持的版本,您必须这样编写查询

/* Edge 16 and higher */
@supports (display: -ms-grid) and (display: grid) {
  div {
    width: auto;
  }
}

/* Edge 15 and lower */
@supports (display: -ms-grid) and (not (display: grid)) {
  div {
    margin: 0
  }
}

这里有一个方便的小演示,显示了在您打开它的浏览器中触发了哪个特性查询。

查看代码笔 display: grid 支持测试,由 Manuel Matuzovic (@matuzo) 在 CodePen 上创建。

顺便说一下,您不应该过度(误用)特性查询进行浏览器嗅探,因为 浏览器检测是错误的

指定每列的精确项目数量

网格非常适合页面布局,但也非常适合组件级别。我最喜欢的示例之一是能够在多列组件中指定每列的精确项目数量。

假设我们有一个包含 11 个项目的列表,并且我们希望在每四个项目后添加一个新列。在对父元素设置 `display: grid` 后,我们要做的第一件事是更改网格自动放置算法的工作方式。默认情况下,它会依次填充每行,并在需要时添加新行。如果我们将 `grid-auto-flow` 设置为 `column`,网格将改为依次填充每列,这正是我们想要的。我们必须做的最后一件事是指定每列的项目数量。这可以通过使用 `grid-template-rows` 属性定义所需的显式行数来实现。我们可以显式设置每行的高度,或者使用 `auto` 关键字使它们与内容一样大。

ul {
  display: grid;
  grid-template-rows: auto auto auto auto;

  /* or shorter and easier to read: */
  /* grid-template-rows: repeat(4, auto); */
  grid-auto-flow: column;
}

如果我们必须将每列的项目数量更改为 5,我们只需在轨道列表中添加另一个轨道,或者使用 重复表示法,只需将第一个参数更改为所需的值 `(grid-template-rows: repeat(5, auto))`。

查看代码笔 每列限制的项目数量,由 Manuel Matuzovic (@matuzo) 在 CodePen 上创建。

使用 CSS 网格创建粘性页脚

有很多方法可以用 CSS 创建粘性页脚 创建粘性页脚的方法。其中一些方法很笨拙而且复杂,但使用网格就很直接了。

假设我们有一个*经典*的页眉、主要内容和页脚页面结构。

<body>
  <header>HEADER</header>
  <main>MAIN</main>
  <footer>FOOTER</footer>
</body>

首先,我们将 `html` 和 `body` 的 `height` 设置为视窗的至少 `100%`,以确保页面始终使用完整的垂直空间。然后,我们将 `grid-template-rows` 应用于将 `body` 分割成三行。第一行(`header`)和最后一行(`footer`)可以具有我们想要的任何大小。如果我们希望它们始终与内容一样大,我们只需将高度设置为 `auto`。中间的行(`main`)应该始终填充剩余的空间。我们不必计算高度,因为我们可以使用 分数单位 来实现这一点。

html {
  height: 100%;
}

body {
  min-height: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
}

因此,主要内容会增长,页脚会相应地调整并保持在视窗的底部。

查看代码笔 CSS 网格布局粘性页脚,由 Manuel Matuzovic (@matuzo) 在 CodePen 上创建。

网格项目的自动最小尺寸

最近,Florian 在 Twitter 上发帖说他想知道为什么 在网格项目中截断单行文本如此复杂。他的示例完美地说明了网格项目的一个有趣事实。

初始情况是一个三列网格,每个网格项目中都包含一个段落。

<div class="grid">
  <div class="item">
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo ipsum exercitationem voluptate, autem veritatis enim soluta beatae odio accusamus molestiae, perspiciatis sunt maiores quam. Deserunt, aliquid inventore. Ullam, fugit dicta.
    </p>
  </div>
</div>
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 20px;
}

每段文本应仅为单行,如果段落比其父级项目长,则在行末显示省略号。Florian 通过将 white-space 设置为 nowrap 来解决这个问题,这会强制使用单行,隐藏 overflow 并将 text-overflow 设置为 ellipsis

p {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

这在块级元素上可以完美地工作,但在网格示例中,列会扩展到单行段落的宽度。

查看 Manuel Matuzovic 在 CodePen 上创建的 网格项目的自动最小尺寸 演示。

总的来说,这是因为网格项目不能小于其子元素。网格项目(或弹性项目)的默认 min-width 设置为 auto,根据规范...

…对溢出可见且跨越至少一条最小轨道大小函数为 auto 的轨道,在指定的轴上应用自动最小尺寸

这使得网格和弹性项目更灵活,但有时不希望内容能够拉伸其父级项目的宽度。为了避免这种情况,我们可以将网格项目的 overflow 属性更改为除 visible 之外的任何其他值,或者将 min-width 设置为 0

查看 Manuel Matuzovic 在 CodePen 上创建的 CSS 网格中截断文本 演示。

在网格规范中详细了解网格项目的自动最小尺寸

总结

希望这些最新的收获能帮助你像我一样更轻松地编写和使用网格。这个新规范中有很多细节,但随着使用次数的增多,它会变得更加有趣和易于理解。