IE 中的 CSS Grid:打破常见的 IE Grid 误解

Avatar of Daniel Tonon
Daniel Tonon

DigitalOcean 为您旅程的每个阶段提供云产品。从 $200 免费积分 开始!

这是关于如何在 Internet Explorer (IE) 中使用 CSS grid 的三部分系列文章的第一篇。想象一下编写 CSS grid 代码而无需编写回退布局!我们中的许多人认为,这只是一个遥远的未来,还需要很多年才能实现。如果唯一阻止你实现这一目标的是 IE11(查看 caniuse.com),那么你很幸运!这一天已经到来了!或者至少在你看完本系列文章后就会到来。😉

系列文章

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

首先,这第一部分将揭穿围绕 IE11 本机网格实现的一些常见误解。

在第二部分中,我将揭开使用 IE11 中的 CSS grid 非常难的这个神话。IE11 不再需要糟糕的回退布局!

在第三部分中,我将向您展示我用来创建简单自动放置网格的酷炫 flexbox 技术。这些假自动放置网格具有固定像素的网格间隙,与使用真实 CSS grid 创建的网格间隙完美对齐。它们在 IE11 中完美运行,完全响应,并且根据屏幕宽度更新其列数只需要更改媒体查询中的一个宽度值。

介绍到此为止,让我们开始了解这些误解吧!

IE确实具有隐式网格

在 CSS grid 中,显式网格是您使用所有 grid-template-* 属性手动定义的网格。隐式网格是浏览器处理放置在显式网格外部的单元格的方式。

在现代浏览器中使用 CSS grid 时,隐式网格非常明显,因为网格将继续在新的行上自动创建和放置网格单元格,而无需定义它们。IE 不支持自动放置,因此很容易假设 IE 没有隐式网格。但实际上它有——您只需要在使用它时更明确一些。

查看 CodePen 显式与隐式网格,作者是 Daniel Tonon (@daniel-tonon),发布在 CodePen 上。

使用 IE 隐式网格最常见的用例是使用它为您生成行。如果您希望网格中的所有行的高度都由其内容的高度决定,则不需要费心定义 -ms-grid-rows(IE 版本的 grid-template-rows)。在放置网格单元格时,IE 会自动为您生成行。

需要注意的重要一点是,现代浏览器可以访问 grid-auto-rowsgrid-auto-columns 属性。这些属性允许您控制浏览器如何处理隐式网格中行和列的大小。IE 不了解这些属性。IE 的隐式行和列只能始终以 auto 大小存在。

IE 具有 repeat 功能

不要害怕!您无需为您的 12 列网格编写 12 次 1fr 20px(IE 不支持本机网格间隙)。IE 预先打包了完整的 repeat() 功能。它只是隐藏在不同的语法后面。

在列和行中重复值的现代语法是 repeat(12, 1fr 20px),意思是“重复 1fr 20px 模式 12 次”。IE 版本的语法是 (1fr 20px)[12]。IE 版本具有相同的功能,只是语法不同。

/* This grid... */
.grid-one {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: 1fr 20px 1fr 20px 1fr 20px 1fr;
  grid-template-columns: 1fr 20px 1fr 20px 1fr 20px 1fr;
}

/* ...is exactly the same as this grid: */
.grid-two {
  display: -ms-grid;
  display: grid;

  /* IE repeat syntax */
  -ms-grid-columns: 1fr (20px 1fr)[3];

  /* Modern repeat syntax */
  grid-template-columns: 1fr repeat(3, 20px 1fr);
}

除了语法之外,现代浏览器和 IE 实现 repeat() 函数的方式之间只有一个区别。现代浏览器在该函数中添加了 auto-fitauto-fill 关键字。由于 IE 不支持自动放置,因此这些关键字对 IE 来说毫无意义,所以请避免使用它们。

minmax() 在 IE 中得到本机支持

minmax() 是一个 CSS 尺寸函数,目前仅限于 CSS grid(至少目前是这样)。它的功能不言而喻。您在第一个参数中提供最小值,在第二个参数中提供最大值。应用此值的行或列将能够在这两个值之间收缩和扩展,这取决于可用的空间增加或减少。尝试调整下面的 CodePen 大小,以查看它在实际中的效果。

查看 CodePen minmax() 演示,作者是 Daniel Tonon (@daniel-tonon),发布在 CodePen 上。

人们通常认为这个很棒的小功能在 IE 中不受支持,但实际上它得到了本机支持。我猜想这至少是以下两个原因之一造成的

  1. 这是一个很酷的功能,他们认为 IE 无法拥有这样的酷炫功能,因为 IE 很烂。
  2. 每个人都看到了这个神奇的代码片段,并在意识到它在 IE 中无法运行时,他们的梦想破灭了:grid-template-columns: repeat( auto-fit, minmax(250px, 1fr) );

(如果您以前从未见过这个代码片段,请观看 这段简短的视频,准备接受思维上的洗礼。)

由于神奇的代码片段在 IE 中无法运行,因此人们可能会认为代码片段中的内容都不支持 IE。实际上,代码片段无法在 IE 中复制的唯一原因是 IE 不支持 auto-fit 关键字和自动放置。

min-content 和 max-content 都 100% 支持 IE

IE 完全本机支持 min-contentmax-content 值。

min-content 是一个关键字值,它将缩小列/行,使其达到内容可以缩小的最小可能宽度。如果应用于列,则基本上意味着该列的宽度将与最长的单词的宽度相同。

查看 CodePen min-content 演示,作者是 Daniel Tonon (@daniel-tonon),发布在 CodePen 上。

另一方面,max-content 将扩大列/行,使其达到其内容所占用的最大可能宽度,并且不会再扩大。如果您曾经在一段较长的文本上设置 white-space: nowrap,则这看起来非常相似。

查看 CodePen max-content 演示,作者是 Daniel Tonon (@daniel-tonon),发布在 CodePen 上。

我原本并不期望 IE 支持这些值,主要是因为 minmax() 下的第一个原因。当我在研究 IE11 网格支持时,我很高兴地发现自己错了。与 minmax() 结合使用后,现代浏览器可以创建的许多网格都可以由 IE 处理(只要这些网格不涉及自动放置)。

fit-content()不支持 IE,但是

fit-content() 在 IE 中无法正常运行。😢

幸运的是,fit-content() 是一种简写语法,当您将其写成完整形式时,IE确实支持它!🎉

完整形式是在网格模板中将 auto(更准确地说,是 minmax(min-content, max-content))应用于列/行,然后在子元素上设置 max-width: [value]

以下是如何在现代浏览器中使用 fit-content() 函数的示例

/* This is not IE-friendly */
.grid {
  display: grid;
  grid-template-columns: 100px fit-content(300px) 1fr;
}

.cell {
  grid-column: 2;
}

这里 fit-content() 基本上表示的是,“让中间列占用其内容的最大可能宽度(即其 max-content 值),直到它达到 300px,此时不再增长,除非被迫增长。”

查看 CodePen fit-content() 现代示例 1,作者是 Daniel Tonon (@daniel-tonon),发布在 CodePen 上。

如果您是在移动设备上阅读本文,请以横屏模式查看本节的 CodePen 演示,以便更好地理解。

为了让 IE 以相同的方式运行,您需要像这样编写代码

/* IE-friendly `fit-content()` alternative */
.grid {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: 100px auto 1fr;
  grid-template-columns: 100px auto 1fr;
}

.cell {
  -ms-grid-column: 2;
  grid-column: 2;
  max-width: 300px;
}

查看笔 fit-content IE hack 由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建。

请注意,这不是在 IE 中复制 fit-content() 的万无一失的方法。如果另一个网格单元格具有占用宽度大于其他单元格 max-width 设置的内容,则网格列将扩展以适合较大的单元格。它不会像使用 fit-content() 那样固定在 300px。

查看笔 Broken fit-content hack 由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建。

将此与现代 fit-content() 函数进行比较,该函数会限制整个列。

查看笔 fit-content() modern example 由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建。

趁此机会,我应该澄清一下围绕 fit-content() 函数本身的一个常见误解。误解是,它所应用的列(或行)永远不能超过您提供给函数的值。事实并非如此。如果将列设置为 fit-content(300px) 的宽度,并且该列内的网格单元格设置为 400px 的宽度,则列宽度将为 400px,而不是许多人可能期望的 300px。

查看笔 Broken modern fit-content 由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建。

IE auto != 现代 auto

IE 中的 auto 值的行为与现代浏览器中的 auto 略有不同。在 IE 中,auto 严格等于 minmax(min-content, max-content)。在 IE 中设置为 auto 的列或行永远不会收缩到小于 min-content 的大小。它也不能扩展到大于 max-content 的大小。

现代浏览器对 auto 值的处理方式略有不同。在大多数情况下,当单独使用该值时,它们仍然将 auto 视为 minmax(min-content, max-content)。不过,有一个细微但至关重要的区别:现代浏览器中的 auto 可以通过 align-contentjustify-content 属性进行拉伸。IE 不允许这样做。

当在现代浏览器中使用 auto 对列进行大小调整时,如果内容不足以填充列,auto 的行为更像 1fr。IE 不会。IE 将始终将列收缩到 max-content 的大小。

因此,如果您有以下代码定义您的网格

.grid {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: auto auto;
  grid-template-columns: auto auto;
}

您将在现代浏览器中得到以下结果

现代浏览器自动宽度列,内容很少。列填充网格。

…以及在 IE 中得到以下结果

IE 自动宽度列,内容很少。列缩小到内容大小。

好的,现代浏览器看起来很像我们使用 1fr 时得到的结果。那么,我们可以在 IE 中使用 minmax(min-content, 1fr) 吗?这样会像在现代浏览器中那样将其拉伸出来,不是吗?

是的,但我们会遇到以下问题

.grid {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: minmax(min-content, 1fr) minmax(min-content, 1fr);
  grid-template-columns: auto auto;
}

现代浏览器

现代浏览器自动宽度列,一个单元格中有很多内容。列的宽度不同。

IE

IE minmax(min-content, 1fr) 列,一个单元格中有很多内容。列的宽度相同。

顺便说一下,minmax(min-content, 1fr) 本质上是 1fr1fr,并不等于 auto。我也尝试在 IE 中使用 minmax(min-content, 100%),但这只是导致与使用 1fr 相同的网格外观。据我所知,不可能在 IE 中复制现代浏览器的 auto 功能。

不过,IE 和现代版本的 auto 值之间还有一个至关重要的区别。由于 IE 版本的 auto 明确等于 minmax(min-content, max-content),因此 auto 不能在 minmax() 表达式中使用minmax() 不能在另一个 minmax() 函数内使用,因此 auto 被排除在外。

现代浏览器更加微妙。它们认识到 auto 在不同上下文中可能意味着不同的东西。如果单独使用,它本质上等于 minmax(min-content, max-content),但具有额外的拉伸能力。当用作最大值时,auto 等同于 max-content。当用作最小值时,它本质上等于 min-content

如果您现在发誓永远不再在网格模板中使用 auto,您可能需要重新考虑一下。只有三种情况下,auto 在现代浏览器和 IE 之间的行为会有所不同。这些情况是

  1. autogrid-template-columns 中使用,但在同一声明中没有 fr 单位。
  2. autogrid-template-rows 中使用,但在同一声明中没有 fr 单位并且网格的高度大于其网格单元格的高度。
  3. autominmax() 函数中使用。

就是这样!这些是 auto 在 IE 中的行为与在现代浏览器中行为不同的唯一时间。autominmax(min-content, max-content) 容易写得多,因此,为了几个容易避免的小浏览器不一致性而谴责它并不值得。

(更新) IE 网格在 display: inline 元素上不起作用

如果您使用 <span><a> 元素作为网格中的网格单元格,您会在 IE 中进行测试时惊讶地发现您的网格看起来不像预期。您所有的 块级元素(例如 <p><div><ul> 等)似乎按预期出现在网格中,但您的 内联元素(例如 <span><a><label> 等)将不会。

Span element works correctly in modern browsers but not in IE if using default CSS display settings.

不幸的是,IE 网格无法将 display: inline 元素正确地放置到网格中。<span><a> 元素默认情况下在浏览器中设置为 display: inline。不过,您可以在 IE 中通过将内联元素显式设置为 display: block 来轻松解决此问题。

Span element works correctly in both modern browsers and in IE if the span is set to display block.

查看笔
inline grid items don’t work in IE
由 Daniel Tonon (@daniel-tonon) 创建。
CodePen 上。

默认情况下,HTML 5 元素(如 <main><header><footer>)通常在浏览器中设置为 display: block。但是,由于这些元素是在 IE11 发布之后发布的,因此 IE11 无法识别它们。无法识别的元素会还原为在不支持的浏览器中相当于 <span> 元素。这意味着,如果它们成为网格项目,它们默认情况下将不会在 IE 中工作。

您可以通过将这些现代元素显式设置为 display: block 来使它们按预期工作。或者,您可以将 normalize.css 添加到您的项目中,它会为您完成此操作。它还会执行一些其他小操作,使您的开发体验更加愉快。

我们学到了什么?

  • IE 确实具有隐式网格。
  • IE 支持重复功能。
  • minmax()min-contentmax-content 都得到原生支持。
  • fit-content() 不支持,但您可以使用 automax-width 设置来解决这个问题。
  • IE auto 不等于现代浏览器中的 auto
  • IE 网格在 display: inline 元素上不起作用。

不过,现在还不要急于使用网格。在您开始安全地将 IE 网格实现到您的网站之前,您还需要了解很多东西。请务必关注第 2 部分!我将向您展示使用 CSS 网格安全地为 IE 和现代浏览器构建网站所需的一切。最棒的是,您将不再需要糟糕的备用布局!

系列文章

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