IE 中的 CSS Grid:现在支持重复区域名称!

Avatar of Daniel Tonon
Daniel Tonon

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

Autoprefixer 现在已经更新到 9.3.1 版本,自从我写了最初的三部分 IE 中的 CSS Grid 系列 以来,已经有了很多更新——其中最重要的更新是新的 grid-areas 系统。这主要归功于 Bogdan Dolin,他一直在努力解决大量的 Autoprefixer 问题。Autoprefixer 的网格转换之前就很强大,但现在它们变得更加强大!

文章系列

  1. 揭穿常见的 IE Grid 误解
  2. CSS Grid 和新的 Autoprefixer
  3. 用间隙模拟自动放置网格
  4. 现在支持重复区域名称!(本文)

Autoprefixer 如何支持重复区域名称

系列的第 2 部分 中,我指出了为什么 Autoprefixer 无法处理跨多个选择器使用的重复区域名称。

总而言之,这是我在文章中给出的示例

.grid-alpha {
  grid-template-areas: "delta echo";
}

.grid-beta {
  grid-template-areas: "echo delta";
}

.grid-cell {
  /* What column does .grid-cell go in? */
  -ms-grid-column: ???;
  grid-area: echo;
}

我们认为,由于 Autoprefixer 无法访问 DOM,因此无法知道网格单元格属于哪个网格,因此也无法知道网格单元格应该放在哪一列。

然而,我意识到了一些事情。网格单元格只受其直接父元素的影响(忽略 display: contents)。这意味着如果网格单元格存在,它将始终是网格模板元素的直接子元素。这给了我一个关于如何解决网格区域名称冲突的想法!😁

.grid-alpha {
  grid-template-areas: "delta  echo";
}

.grid-beta {
  /* Uh oh, duplicate area names! */
  grid-template-areas: "echo  delta";
}

.grid-cell {
  /* We will use the first occurrence by default */
  -ms-grid-column: 2;
  grid-area: echo;
}

/*
  We have detected a conflict!
  Prefix the class with the parent selector.
*/
.grid-beta > .grid-cell {
  /* NO MORE CONFLICT! */
  -ms-grid-column: 1;
}

整个 grid-areas 系统需要重新编写才能实现这一点,但这绝对是值得的。

这个新系统的工作原理是,.grid-cell 将默认使用它遇到的第一个 grid-template-areas 属性。当它遇到冲突的网格模板时,它将创建一个新规则,将父选择器放在子选择器之前,如下所示

[full parent selector] > [direct child selector]

这就是我们仅通过查看 CSS 并了解 CSS Grid 工作原理就可以知道的

  • 为了使 CSS Grid 工作,网格单元格必须是父网格容器的直接后代(假设不使用 display: contents)。
  • grid-beta > .grid-cell 将仅对直接放置在 .grid-beta 元素内的 .grid-cell 元素起作用。
  • .grid-beta > .grid-cell 对直接放置在 .grid-alpha 元素内的 .grid-cell 元素没有影响。
  • .grid-beta > .grid-cell深度嵌套在 .grid-beta 元素内的 .grid-cell 元素没有影响。
  • .grid-beta > .grid-cell 将覆盖单独的 .grid-cell CSS 规则的样式,这既是因为规则顺序,也是因为特异性。

由于这些原因,Autoprefixer 可以非常安全地解决这些冲突,而无需访问 DOM。

列表中的最后一点可能有点危险。它增加了特异性,这意味着它可能会导致某些 IE 样式以不同于现代覆盖样式工作的方式覆盖其他样式。由于生成的规则只包含 IE 特定的网格样式,并且它们只在非常特定的情况下应用,因此这不太可能在 99.999% 的情况下造成问题。但仍然存在边缘情况的可能性。

如果您发现需要增加网格单元格选择器的特异性,以下是如何操作。

不要写成这样

.grid {
  grid-template-areas: "area-name";
}

.grid-cell {
  grid-area: area-name;
}

…而是将规则写成这样

.grid {
  grid-template-areas: "area-name";
}

.grid > .grid-cell {
  grid-area: area-name;
}

Autoprefixer 将保留选择器并输出类似于以下内容的内容

.grid {
  grid-template-areas: "area-name";
}

.grid > .grid-cell {
  -ms-grid-column: 1;
  -ms-grid-row: 1;
  grid-area: area-name;
}

令人兴奋的新可能性!

那么为什么重复区域名称支持如此令人兴奋呢?

嗯,一方面,当在旧版本的 Autoprefixer 中意外使用重复区域名称时,它真的很烦人。它将在 IE 中中断,并且在旧版本的 Autoprefixer 中,它将静默失败。

然而,它令人兴奋的主要原因是它开辟了 IE 友好 CSS Grid 的全新世界!

使用修饰符类调整网格模板

这正是让我想要将重复区域名称支持添加到 Autoprefixer 的用例。想想这个。您有一个典型的网站,包含标题、页脚、主区域以及两侧的侧边栏。

查看 Pen 基本网站布局,作者是 Daniel Tonon (@daniel-tonon),发布于 CodePen

有时我们想要两个侧边栏,有时我们想要一个侧边栏,有时我们不想任何侧边栏。当 Autoprefixer 不支持重复区域名称时,这很难管理,因为我们无法在多个网格模板之间共享区域名称。我们将不得不做类似的事情才能使它工作

/*
  Before Duplicate area names were supported
  - n = no side-bars
  - f = first sidebar only
  - s = second sidebar only
  - fs = first and second sidebars
*/
.main-area {
  display: grid;
  grid-template:
    "content-n" /
      1fr;
}

.main-area.has-first-sidebar {
  grid-template:
    "first-sb-f content-f" /
      300px      1fr;
}

.main-area.has-second-sidebar {
  grid-template:
    "content-s second-sb-s" /
      1fr       300px;
}
.main-area.has-first-sidebar.has-second-sidebar {
  grid-template:
    "first-sb-fs content-fs second-sb-fs" /
      200px       1fr        200px;
}

.main-area > .content {
  grid-area: content-n; /* no side-bars */
}

.main-area > .sidebar.first {
  grid-area: first-sb-f; /* first sidebar only */
}

.main-area > .sidebar.second {
  grid-area: second-sb-s; /* second sidebar only */
}

.main-area.has-first-sidebar > .content {
  grid-area: content-f; /* first sidebar only */
}

.main-area.has-second-sidebar > .content {
  grid-area: content-s; /* second sidebar only */
}

.main-area.has-first-sidebar.has-second-sidebar > .content {
  grid-area: content-fs; /* first and second sidebars */
}

.main-area.has-first-sidebar.has-second-sidebar > .sidebar.first {
  grid-area: first-sb-fs; /* first and second sidebars */
}

.main-area.has-first-sidebar.has-second-sidebar > .sidebar.second {
  grid-area: second-sb-fs; /* first and second sidebars */
}
Autoprefixer 转换
/*
  Before Duplicate area names were supported
  - n = no sidebars
  - f = first sidebar only
  - s = second sidebar only
  - fs = first and second sidebars
*/

.main-area {
  display: -ms-grid;
  display: grid;
  -ms-grid-rows: auto;
  -ms-grid-columns: 1fr;
      grid-template:
    "content-n" /
     1fr;
}

.main-area.has-first-sidebar {
  -ms-grid-rows: auto;
  -ms-grid-columns: 300px 1fr;
      grid-template:
    "first-sb-f content-f" /
      300px      1fr;
}

.main-area.has-second-sidebar {
  -ms-grid-rows: auto;
  -ms-grid-columns: 1fr 300px;
      grid-template:
    "content-s second-sb-s" /
      1fr       300px;
}

.main-area.has-first-sidebar.has-second-sidebar {
  -ms-grid-rows: auto;
  -ms-grid-columns: 200px 1fr 200px;
      grid-template:
    "first-sb-fs content-fs second-sb-fs" /
      200px       1fr        200px;
}

.main-area > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: content-n; /* no side-bars */
}

.main-area > .sidebar.first {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: first-sb-f; /* first sidebar only */
}

.main-area > .sidebar.second {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: second-sb-s; /* second sidebar only */
}

.main-area.has-first-sidebar > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: content-f; /* first sidebar only */
}

.main-area.has-second-sidebar > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: content-s; /* second sidebar only */
}

.main-area.has-first-sidebar.has-second-sidebar > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: content-fs; /* first and second sidebars */
}

.main-area.has-first-sidebar.has-second-sidebar > .sidebar.first {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: first-sb-fs; /* first and second sidebars */
}

.main-area.has-first-sidebar.has-second-sidebar > .sidebar.second {
  -ms-grid-row: 1;
  -ms-grid-column: 3;
  grid-area: second-sb-fs; /* first and second sidebars */
}

🤢 哦,对了,别忘了媒体查询!🤮

这个示例基于我必须为实际项目编写的实际代码……所以是的,我真的想要将重复区域名称支持添加到 Autoprefixer。

现在我们确实有了重复区域名称支持,我们可以将这段代码简化为更友好的内容 😊

/*
  Duplicate area names now supported!
  This code will work perfectly in IE with Autoprefixer 9.3.1
*/

.main-area {
  display: grid;
  grid-template:
    "content" /
      1fr;
}

.main-area.has-first-sidebar {
  grid-template:
    "first-sb content" /
      300px    1fr;
}

.main-area.has-second-sidebar {
  grid-template:
    "content second-sb" /
      1fr     300px;
}

.main-area.has-first-sidebar.has-second-sidebar {
  grid-template:
    "first-sb content second-sb" /
      200px    1fr     200px;
}

.content {
  grid-area: content;
}

.sidebar.first {
  grid-area: first-sb;
}

.sidebar.second {
  grid-area: second-sb;
}
Autoprefixer 转换
.main-area {
  display: -ms-grid;
  display: grid;
  -ms-grid-rows: auto;
  -ms-grid-columns: 1fr;
  grid-template:
    "content" /
      1fr;
}

.main-area.has-first-sidebar {
  -ms-grid-rows: auto;
  -ms-grid-columns: 300px 1fr;
  grid-template:
    "first-sb content" /
      300px    1fr;
}

.main-area.has-second-sidebar {
  -ms-grid-rows: auto;
  -ms-grid-columns: 1fr 300px;
  grid-template:
    "content second-sb" /
      1fr     300px;
}

.main-area.has-first-sidebar.has-second-sidebar {
  -ms-grid-rows: auto;
  -ms-grid-columns: 200px 1fr 200px;
  grid-template:
    "first-sb content second-sb" /
      200px    1fr     200px;
}

.content {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: content;
}

.main-area.has-first-sidebar > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
}

.main-area.has-second-sidebar > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.main-area.has-first-sidebar.has-second-sidebar > .content {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
}

.sidebar.first {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: first-sb;
}

.main-area.has-first-sidebar.has-second-sidebar > .sidebar.first {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.sidebar.second {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: second-sb;
}

.main-area.has-first-sidebar.has-second-sidebar > .sidebar.second {
  -ms-grid-row: 1;
  -ms-grid-column: 3;
}

有了这个 CSS,我们现在能够在网格元素上使用 has-first-sidebarhas-second-sidebar 类来修改浏览器使用的网格模板。我们不再需要担心定义网格单元格放置在哪个网格中。

分配组件可重复使用的区域名称

被迫使用唯一区域名称的局限性之一是,无法为组件提供单个一致的可重复使用的区域名称。我们被迫为每个网格想出唯一的区域名称。

现在 Autoprefixer 拥有了重复区域名称支持,这个限制消失了。我们可以为每个组件提供一个基于其组件名称的单个区域名称。然后,只要我们想将该组件放置在网格布局中,就可以引用该单个区域名称。

/* header.scss */
.header {
  grid-area: header;
}

/* nav.scss */
.nav {
  grid-area: nav;
}

/* sidebar.scss */
.sidebar {
  grid-area: sidebar;
}

/* content.scss */
.content {
  grid-area: content;
}

/* subscribe.scss */
.subscribe {
  grid-area: subscribe;
}

/* footer.scss */
.footer {
  grid-area: footer;
}

/* layout.scss */
.single-sidebar-layout {
  display: grid;
  grid-template-areas:
    "header    header"
    "nav       content"
    "subscribe content"
    "footer    footer";
}

.double-sidebar-layout {
  display: grid;
  grid-template-areas:
    "header header    header"
    "nav    content   sidebar"
    "nav    subscribe sidebar"
    "footer footer    footer";
}
Autoprefixer 转换
/* header.scss */
.header {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  -ms-grid-column-span: 2;
  grid-area: header;
}

.double-sidebar-layout > .header {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  -ms-grid-column-span: 3;
}

/* nav.scss */
.nav {
  -ms-grid-row: 2;
  -ms-grid-column: 1;
  grid-area: nav;
}

.double-sidebar-layout > .nav {
  -ms-grid-row: 2;
  -ms-grid-row-span: 2;
  -ms-grid-column: 1;
}

/* sidebar.scss */
.sidebar {
  -ms-grid-row: 2;
  -ms-grid-row-span: 2;
  -ms-grid-column: 3;
  grid-area: sidebar;
}

/* content.scss */
.content {
  -ms-grid-row: 2;
  -ms-grid-row-span: 2;
  -ms-grid-column: 2;
  grid-area: content;
}

.double-sidebar-layout > .content {
  -ms-grid-row: 2;
  -ms-grid-column: 2;
}

/* subscribe.scss */
.subscribe {
  -ms-grid-row: 3;
  -ms-grid-column: 1;
  grid-area: subscribe;
}

.double-sidebar-layout > .subscribe {
  -ms-grid-row: 3;
  -ms-grid-column: 2;
}

/* footer.scss */
.footer {
  -ms-grid-row: 4;
  -ms-grid-column: 1;
  -ms-grid-column-span: 2;
  grid-area: footer;
}

.double-sidebar-layout > .footer {
  -ms-grid-row: 4;
  -ms-grid-column: 1;
  -ms-grid-column-span: 3;
}

/* layout.scss */
.single-sidebar-layout {
  display: -ms-grid;
  display: grid;
  grid-template-areas:
    "header    header"
    "nav       content"
    "subscribe content"
    "footer    footer";
}

.double-sidebar-layout {
  display: -ms-grid;
  display: grid;
  grid-template-areas:
    "header header    header"
    "nav    content   sidebar"
    "nav    subscribe sidebar"
    "footer footer    footer";
}

以下是我们得到的内容。请注意,这应该在 IE 中查看。

查看 Pen 组件区域名称技术,作者是 Daniel Tonon (@daniel-tonon),发布于 CodePen

重复区域名称限制

目前 Autoprefixer 仍然无法处理一个相当常见的用例。当网格单元格的父选择器与网格模板选择器不匹配时,它会尝试解决重复区域名称

.grand-parent .mother {
  grid-template-areas: "child";
}

.grand-parent .father {
  grid-template-areas: "child child";
}

/* This will work */
.grand-parent .mother .child {
  grid-area: child;
}

/*
  This does not work because:
  - ".uncle" != ".grand-parent .mother"
  - ".uncle" != ".grand-parent .father"
  - "child" is a duplicate area name
*/
.uncle .child {
  grid-area: child;
}

以下是对 Autoprefixer 算法中当前限制的更现实的场景

.component .grid {
  display: grid;
  grid-template-areas:  "one two";
  grid-template-columns: 1fr 1fr;
}

/* This rule triggers duplicate area name conflicts. */
.component.modifier .grid {
  grid-template-areas:  "one ... two";
  grid-template-columns: 1fr 1fr 1fr;
}

/*
  This does not work because:
  - ".component" != ".component .grid"
  - ".component" != ".component.modifier .grid"
  - area names "one" and "two" both have duplicate area name conflicts
*/
.component .cell-one {
  grid-area: one;
}

.component .cell-two {
  grid-area: two;
}

目前实际上只有三种方法可以解决这个冲突。

选项 1:从子元素中删除父选择器

在没有用于将样式范围限定到特定组件的任何安全措施的情况下,这是解决此问题的最危险的方法。我不推荐它。

.component .grid {
  display: grid;
  grid-template-areas:  "one two";
  grid-template-columns: 1fr 1fr;
}

.component.modifier .grid {
  grid-template-areas:  "one ... two";
  grid-template-columns: 1fr 1fr 1fr;
}

.cell-one {
  grid-area: one;
}

.cell-two {
  grid-area: two;
}
Autoprefixer 转换
.component .grid {
  display: -ms-grid;
  display: grid;
  grid-template-areas:  "one two";
  -ms-grid-columns: 1fr 1fr;
  grid-template-columns: 1fr 1fr;
}

.component.modifier .grid {
  grid-template-areas:  "one ... two";
  -ms-grid-columns: 1fr 1fr 1fr;
  grid-template-columns: 1fr 1fr 1fr;
}

.cell-one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: one;
}

.component.modifier .grid > .cell-one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.cell-two {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: two;
}

.component.modifier .grid > .cell-two {
  -ms-grid-row: 1;
  -ms-grid-column: 3;
}

选项 2:返回使用唯一区域名称

这个解决方案很丑陋,但如果你无法控制 HTML,那么这可能是处理问题最好的方式。

.component .grid {
  display: grid;
  grid-template-areas:  "one two";
  grid-template-columns: 1fr 1fr;
}

.component .cell-one {
  grid-area: one;
}

.component .cell-two {
  grid-area: two;
}

.component.modifier .grid {
  grid-template-areas:  "modifier_one ... modifier_two";
  grid-template-columns: 1fr 1fr 1fr;
}

.component.modifier .cell-one {
  grid-area: modifier_one;
}

.component.modifier .cell-two {
  grid-area: modifier_two;
}
Autoprefixer 转换
.component .grid {
  display: -ms-grid;
  display: grid;
  grid-template-areas:  "one two";
  -ms-grid-columns: 1fr 1fr;
  grid-template-columns: 1fr 1fr;
}

.component .cell-one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: one;
}

.component .cell-two {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: two;
}

.component.modifier .grid {
  grid-template-areas:  "modifier_one ... modifier_two";
  -ms-grid-columns: 1fr 1fr 1fr;
  grid-template-columns: 1fr 1fr 1fr;
}

.component.modifier .cell-one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: modifier_one;
}

.component.modifier .cell-two {
  -ms-grid-row: 1;
  -ms-grid-column: 3;
  grid-area: modifier_two;
}

选项 3:使用 BEM 样式命名约定

是的,如果你使用 BEM 命名约定(或类似约定),这对你来说几乎永远不会是一个问题。如果这是一个选项,这无疑是处理该问题的首选方法。

.component__grid {
  display: grid;
  grid-template-areas:  "one two";
  grid-template-columns: 1fr 1fr;
}

.component__grid--modifier {
  grid-template-areas:  "one ... two";
  grid-template-columns: 1fr 1fr 1fr;
}

.component__cell-one {
  grid-area: one;
}

.component__cell-two {
  grid-area: two;
}
Autoprefixer 转换
.component__grid {
  display: -ms-grid;
  display: grid;
  grid-template-areas:  "one two";
  -ms-grid-columns: 1fr 1fr;
  grid-template-columns: 1fr 1fr;
}

.component__grid--modifier {
  grid-template-areas:  "one ... two";
  -ms-grid-columns: 1fr 1fr 1fr;
  grid-template-columns: 1fr 1fr 1fr;
}

.component__cell-one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: one;
}

.component__grid--modifier > .component__cell-one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.component__cell-two {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
  grid-area: two;
}

.component__grid--modifier > .component__cell-two {
  -ms-grid-row: 1;
  -ms-grid-column: 3;
}

我对 BEM 有些问题,但通过对 语法进行一些调整,它可以成为一种非常好的方法来控制 CSS 特定性和范围。

其他 Autoprefixer 更新

在我写完关于 IE 的 CSS Grid 原文系列之后,Autoprefixer 已经进行了一些其他的更新。

不过,在深入探讨之前,以下是在 CodePen 中设置方法,以防您想自己尝试一下。

在 CodePen 中使用 Autoprefixer Grid 翻译

CodePen 已经升级到 Autoprefixer 的 9.3.1 版本。现在,您可以轻松地将 IE 友好的 CSS Grid 样式集成到您的项目中。首先,确保在 CodePen 设置中启用了 Autoprefixer(设置 > CSS > [供应商前缀] > Autoprefixer)。

步骤 1:在 CodePen 中启用 Autoprefixer

然后,将全新的 /* autoprefixer grid: on */ 控制注释添加到 CSS 面板的顶部。稍后我会详细介绍这个很棒的新功能。

步骤 2:添加控制注释

更新:CodePen 现在也支持较新的 /* autoprefixer grid: autoplace */ 控制注释。这意味着您现在可以使用 CodePen 来试验 Autoprefixers 的自动放置功能。😃

现在,您可以编写现代的 IE 友好的 CSS Grid 代码,CodePen 将自动为您添加所有 IE 前缀。

“查看编译后的 CSS”按钮
编译后的 CSS 视图

但是,为了在 IE 中实际测试您的项目,您需要在 “调试模式” 中查看该项目(更改视图 > 调试模式)。该项目需要保存才能访问此视图。

启用调试模式以在 IE 中进行测试

如果您想尝试一个可以显示实时 Autoprefixer 输出的工具,尝试一下专门为此设计的在线工具。在左侧输入 CSS 代码。它将在您键入时在右侧输出 Autoprefixer 翻译后的 CSS 代码。

autoprefixer.github.io

新的 Autoprefixer 控制注释

我们并不总是能够更改 Autoprefixer 的配置设置。如果你之前曾经尝试在 CodePen 中进行一些 IE 友好的 CSS Grid 实验,你会知道无法直接访问 Autoprefixer 设置的痛苦。还有一些框架(如 Create React App 和 Angular)不允许用户更改 Autoprefixer 设置。还存在一定的技能门槛,阻止一些用户使用 Grid,因为他们不确定如何启用 Grid 翻译。

这个限制给许多用户带来了困扰,但后来 Andrey Alexandrov 提交了一个 pull request,引入了新的控制注释。这个新的控制注释使用户能够轻松地从CSS 文件中启用和禁用网格翻译。这比通过配置设置进行操作要容易得多。无论用户如何编译 CSS,它都对所有用户可用。

添加 /* autoprefixer grid: autoplace */ 将为整个块启用网格翻译,而 /* autoprefixer grid: off */ 将为该块禁用网格翻译。在一个块中,只有第一个网格控制注释将被应用。

/* Globally enable grid prefixes */
/* autoprefixer grid: autoplace */

.grid {
  display: grid;
}

.non-ie .grid {
  /* Turn off grid prefixes but only for this block */
  /* autoprefixer grid: off */
  display: grid;

  /*
    Grid control comments affect the whole block.
    This control comment is ignored
  */
  /* autoprefixer grid: autoplace */
  grid-column: 1;
}

上面的代码将转换为以下代码(我已经过滤掉了解释注释)

/* autoprefixer grid: autoplace */

.grid {
  display: -ms-grid;
  display: grid;
}

.non-ie .grid {
  /* autoprefixer grid: off */
  display: grid;

  /* autoprefixer grid: autoplace */
  grid-column: 1;
}

@supports 可以禁用网格翻译

新的控制注释并不是选择性阻止 Autoprefixer 输出网格翻译代码的唯一方法。

Autoprefixer 将永远无法支持隐式网格自动放置。如果您使用 @supports 语句检查类似 grid-auto-rows: 0 的内容,Autoprefixer 不会为该语句中输入的代码输出 Grid 翻译。

.prefixed .grid {
  display: -ms-grid;
  display: grid;
}

/* Checking grid-auto-* support prevents prefixes */
@supports (grid-auto-rows: 0) {
  .modern .grid {
    display: grid;
  }
}

/* Checking basic grid support still outputs prefixes */
@supports (display: grid) {
  .still-prefixed .grid {
    display: -ms-grid;
    display: grid;
  }
}

为了支持 IE,Autoprefixer 有时可能会生成大约 50 行额外的 CSS 代码。如果您在 @supports 语句中编写 Grid 代码,您需要关闭 IE 翻译,以减轻 CSS 的重量。如果您不想使用 @supports (grid-auto-rows: 0),那么可以在 @supports 语句中使用控制注释。

@supports (display: grid) {
  .prefixed .grid {
    display: -ms-grid;
    display: grid;
  }
}

@supports (display: grid) {
  /* autoprefixer grid: off */
  .modern .grid {
    display: grid;
  }
}

Autoprefixer 现在继承 grid-gaps

在原文系列中,我曾说过 Autoprefixer 无法继承 grid-gap 值。在 9.1.1 版本中,grid-gap 值能够通过媒体查询继承。在 9.3.1 版本中,它们也能够通过更具体的选择器继承。

.grid {
  display: grid;
  grid-gap: 20px; /* grid-gap is stated here */
  grid-template:
    "one two" /
    1fr  1fr;
}

@media (max-width: 600px) {
  .grid {
    /* grid-gap is now inhereited here */
    grid-template:
      "one"
      "two" /
       1fr;
  }
}

.grid.modifier {
    /* grid-gap is now inhereited here as well */
    grid-template:
      "one"
      "two" /
       1fr;
}

.one { grid-area: one; }
.two { grid-area: two; }
Autoprefixer 转换
.grid {
  display: -ms-grid;
  display: grid;
  grid-gap: 20px; /* grid-gap is stated here */
  -ms-grid-rows: auto;
  -ms-grid-columns: 1fr 20px 1fr;
      grid-template:
    "one two" /
    1fr  1fr;
}

@media (max-width: 600px) {
  .grid {
    /* grid-gap is now inhereited here */
    -ms-grid-rows: auto 20px auto;
    -ms-grid-columns: 1fr;
        grid-template:
      "one"
      "two" /
       1fr;
  }
}

.grid.modifier {
    /* grid-gap is now inherited here as well */
    -ms-grid-rows: auto 20px auto;
    -ms-grid-columns: 1fr;
        grid-template:
      "one"
      "two" /
       1fr;
}

.one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  grid-area: one;
}

.grid.modifier > .one {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.two {
  -ms-grid-row: 1;
  -ms-grid-column: 3;
  grid-area: two;
}

.grid.modifier > .two {
  -ms-grid-row: 3;
  -ms-grid-column: 1;
}

@media (max-width: 600px) {
  .one {
    -ms-grid-row: 1;
    -ms-grid-column: 1;
  }
  
  .two {
    -ms-grid-row: 3;
    -ms-grid-column: 1;
  }
}

grid-template: span X; 现在有效

本系列的第 2 部分 中,我曾提到以下语法无效

.grid-cell {
  grid-column: span 2;
}

这个问题在 9.1.1 版本中已修复。它现在会转换为以下代码

.grid-cell {
  -ms-grid-column-span: 2;
  grid-column: span 2;
}

混合使用手动和区域放置的新警告

一位用户抱怨说 Autoprefixer 没有正确处理网格区域。经过进一步调查,我们意识到他们在同一个 CSS 规则中同时应用了 grid-areagrid-column 设置。

.grid {
  display: grid;
  grid-template-areas: "a b";
}

/* This doesn't work very well */
.grid-cell {
  grid-column: 2;
  grid-area: a;
}

要么单独使用 grid-area,要么使用 grid-columngrid-row。切勿同时使用两者。

如果您好奇,以下是 Autoprefixer 为上面的代码输出的内容

.grid {
  display: -ms-grid;
  display: grid;
  grid-template-areas: "a b";
}

/* This doesn't work very well */
.grid-cell {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  -ms-grid-column: 2;
  grid-column: 2;
  grid-area: a;
}

有一个例外。您可能需要一个网格单元格与其他网格单元格重叠。由于 Autoprefixer 使整体单元格放置变得多么容易,因此您需要使用 grid-template-areas 来放置网格单元格。但是,您不能真正使用 grid-template-areas 创建单元格重叠。要创建这种重叠,您可以在 grid-area 声明之后使用 grid-[column/row]-end: span X;强制重叠。

.grid {
  display: grid;
  grid-template-areas:
    "a . ."
    "a b b"
    "a . .";
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
}

.grid-cell-a {
  grid-area: a;
  /* place cell span after the grid-area to force an overlap */
  grid-column-end: span 2;
}

查看由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建的项目 column-span + grid-area 实验

但是,如果您在网格中声明了网格间距,则需要手动编写列/行跨度前缀,同时要考虑 Autoprefixer 生成的额外列/行(IE 不支持 grid-gap)。GitHub 上有 关于这个问题

.grid {
  display: grid;
  grid-template-areas:
    "a . ."
    "a b c"
    "a . .";
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-gap: 10px;
}

.grid-cell-a {
  grid-area: a;
  /* IE column span added manually */
  -ms-grid-column-span: 3; /* IE spans 2 columns + the gap */
  grid-column-end: span 2; /* Modern browsers only span 2 columns */
}

查看由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建的项目 column-span + grid-area 实验 2

该技术目前在 Autoprefixer 中会产生一条难以隐藏的警告消息。 此问题 已在 GitHub 上提出。

使用 [align/justify/place]-[content/items] 时出现新的警告

不幸的是,IE 无法从父容器对网格单元格进行对齐。在 IE 中对齐网格单元格的唯一方法是使用 -ms-grid-row-align-ms-grid-column-align 属性。这些属性在现代网格语法中分别对应 align-selfjustify-self

以下属性如果与 CSS 网格属性一起使用,将在 Autoprefixer 中触发警告

  • align-items
  • align-content
  • justify-items
  • justify-content
  • place-items
  • place-content

align-contentjustify-contentplace-content 属性在 IE 中几乎不可能复制。另一方面,align-itemsjustify-itemsplace-items 属性很容易通过使用子元素的 self 等效属性来复制(place-self 支持已在 9.3.0 中添加)。

/* [align/justify/place]-items is *NOT* IE friendly */

.align-justify-items {
  display: grid;
  align-items: start;
  justify-items: end;
}

.place-items {
  display: grid;
  place-items: start end;
}

/*[align/justify/place]-self *IS* IE friendly */

.align-justify-grid { display: grid; }
.align-justify-grid > * {
  align-self: start;
  justify-self: end;
}

.place-grid { display: grid; }
.place-grid > * {
  place-self: start end;
}
Autoprefixer 转换
/* [align/justify/place]-items is *NOT* IE friendly */

.align-justify-items {
  display: -ms-grid;
  display: grid;
  align-items: start;
  justify-items: end;
}

.place-items {
  display: -ms-grid;
  display: grid;
  place-items: start end;
}

/*[align/justify/place]-self *IS* IE friendly */

.align-justify-grid { display: -ms-grid; display: grid; }
.align-justify-grid > * {
  -ms-grid-row-align: start;
      align-self: start;
  -ms-grid-column-align: end;
      justify-self: end;
}

.place-grid { display: -ms-grid; display: grid; }
.place-grid > * {
  -ms-grid-row-align: start;
  -ms-grid-column-align: end;
  place-self: start end;
}

.grid { [align/justify/place]-items }.grid > * { [align/justify/place]-self } 通常可以互换使用。这种替换并非总是有效,但在大多数情况下,这两种方法的行为非常相似。

下面是一个示例,展示了 IE 友好对齐方法和 IE 不友好对齐方法之间的区别。在现代浏览器中它们看起来相同,但在 IE 中,一个看起来与现代浏览器相同,而另一个则不同。

查看 CodePen 上 Daniel Tonon ( @daniel-tonon ) 编写的 place-items 实验

就是这些了,朋友们

我希望你喜欢阅读有关 Autoprefixer 社区在过去几个月里为该项目做出的惊人改进。新的控制注释使得启用和禁用网格转换变得非常容易。新的网格区域系统也令人兴奋。我喜欢新的网格区域系统带来的所有 IE 友好 CSS 网格选项,我相信你也会喜欢。🙂

文章系列

  1. 揭穿常见的 IE Grid 误解
  2. CSS Grid 和新的 Autoprefixer
  3. 用间隙模拟自动放置网格
  4. 现在支持重复区域名称!(本文)