IE 中的 CSS Grid:使用间隙模拟自动放置网格

Avatar of Daniel Tonon
Daniel Tonon

DigitalOcean 为您旅程的每个阶段提供云产品。从 200 美元的免费信用额度开始

这是关于在 Internet Explorer 11(IE11)中安全使用 CSS Grid 的三部分系列文章的第三部分也是最后一部分,不会让人抓狂。

第一部分,我介绍了一些人们对 IE11 的原生 CSS Grid 实现的常见误解。第二部分,我向世界展示了编写 IE 友好型 CSS Grid 代码实际上是多么容易。

今天,我将暂时离开 CSS Grid,向您展示一种 flexbox 技术,它可以复制基本的 CSS Grid 自动放置功能。这个 CSS Grid 复制品甚至看起来像应用了 grid-gap。但我需要非常清楚地说明:这 *不是* 关于如何在 IE 中实现实际的 CSS Grid 自动放置。

文章系列

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

如何使用间隙创建模拟网格

步骤 1:HTML

我将使用这个基本的 HTML 作为示例




<div class="grid-wrapper">




<div class="grid">



<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>






<div class="grid-cell"></div>



</div>



  
</div>

步骤 2:边框框尺寸

在 CSS 中,我们需要做的第一件事是确保所有框的尺寸都是基于 border-box 而不是 content-box。最好的方法是使用 box-sizing: border-box 继承技术

html {
  box-sizing: border-box;
}

*, *::before, *::after {
  box-sizing: inherit;
}

这将被全局应用。如果您正在处理一个没有将 box-sizing 设置为 border-box 的现有项目,则将代码段中的 html 更改为一个选择器,该选择器将目标元素转换为网格。

步骤 3:Flex

接下来,您需要开启一些 flexbox 设置

.grid {
  /* Forces equal cell heights */
  display: flex;
  flex-wrap: wrap;
}

步骤 4:宽度

现在,设置您的列宽度。我们将创建一个简单的三列网格

.grid-cell {
  /* Sets column count */
  width: calc(100% / 3); /* calc() method */
  width: 33.33%; /* percentage method */
}

calc() 方法允许更轻松地更改列宽度。您声明所需的列数,浏览器会为您进行计算。这在您需要更多列(例如 7 或 8 列)时特别方便。浏览器对 calc() 的支持很强,但不如原始百分比值,自 CSS 诞生以来,浏览器就支持原始百分比值。

此浏览器支持数据来自 Caniuse,其中提供了更多详细信息。数字表示浏览器在该版本及更高版本中支持该功能。

台式机

ChromeFirefoxIEEdgeSafari
19*4*11126*

移动设备/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
1271271276.0-6.1*

百分比方法具有稍微更好的浏览器支持,并且在 IE 中可能更稳定。如果您不需要支持 Opera Mini,我仍然建议首先使用 calc() 方法。在 IE 中测试,如果布局出现问题,首先尝试在 calc 函数中使用 99.999% 而不是 100%calc(99.999% / 3))。如果这不起作用,则尝试切换到百分比方法。在我的所有示例中,我将使用 calc() 方法。请注意,如果您使用的是 CSS 预处理器(如 SCSS),则可以通过让预处理器为您进行数学运算来实现两全其美。但这会导致您无法在浏览器开发者工具中轻松编辑或查看列计数。

/* Set column count using SCSS */
.grid-cell {
  width: (100% / 3);
}

/* CSS output into the browser */
.grid-cell {
  width: 33.3333333333%;
}

让我们为网格单元格添加一些高度和内部 box-shadow,这样我们就可以看到发生了什么。我没有添加边框——我将在稍后使用它。😉

.grid-cell {
  /* So that we can see the grid cells */
  box-shadow: inset 0 0 0 1px #000;
  height: 100px;
}

.grid-wrapper {
  /* Allows us to see the edges of the grid */
  box-shadow: 0 0 10px 2px green;
}

您现在应该看到这样的内容

一个基本的 3 x 2 网格,没有间隙

这很无聊吧?每个人都知道怎么做。这些我一直提到的网格间隙在哪里?我想要我的间隙!!!

步骤 5:边框

这就是有趣的地方。由于我们将 box-sizing 设置为 border-box,因此 33.33% 的宽度现在 *包含* 边框。这意味着我们可以开始安全地混合固定单位和百分比单位!😃

.grid {
  /* Creates an equal outer gap */
  padding: 20px 0 0 20px;
}

.grid-cell {
  /* Creates gaps */
  border: 0 solid transparent;
  border-width: 0 20px 20px 0;
}

这将产生看起来像具有等间距的网格的东西

一个 3 x 2 网格,每个单元格和网格外边缘之间具有等间距

为了帮助您更好地了解发生了什么,请查看以下图片

网格的彩色编码图

网格顶部和左侧的蓝色区域是 .grid 元素的填充。黄色轮廓显示每个 .grid-cell 元素占据的区域。每个单元格底部和右侧的红色区域是每个 .grid-cell 元素的边框。

这可能正是您想要的样式。另一方面,这与具有 grid-gap 设置的网格并不相同。这就是为什么我们还有另一个步骤。

步骤 6:边距和溢出

为了让网格紧贴容器的边缘,我们需要负边距和 overflow: hidden 的帮助

.grid {
  /* Pulls grid cells hard against edges */
  margin: -20px;
}

.grid-wrapper {
  /* Prevents odd margin behavior */
  overflow: hidden;
}

我们需要将 overflow: hidden 应用于容器,以防止这种情况发生

如果溢出未隐藏,则会忽略顶部和底部的负边距

应用负边距和 overflow: hidden 将使我们获得这个美丽的复制品,它模拟了基本的 grid-gap 功能

一个 3 x 2 网格,看起来与具有间隙设置的 CSS 网格相同

网格的顶部和左侧填充实际上是可选的。如果您愿意,您可以选择不使用填充并更改边距值,如下所示

.grid {
  /* Margin needs to be this if leaving off the top and left .grid padding */
  margin: 0 -20px -20px 0;
}

但是,等等!工作还没有完全结束。看看如果我们在其中一个网格单元格中添加背景颜色会发生什么

应用于左上角单元格的粉红色背景溢出到网格间隙中

这并不是我们想要的,所以还有一个步骤。

步骤 7:background-clip

为了防止网格单元格背景渗透到我们的模拟 grid-gap 中,我们需要向它添加 background-clip: padding-box

.grid-cell {
  /* Prevents background bleed */
  background-clip: padding-box;
}

现在我们有了这个

背景渗透问题已解决!

如果您以前从未听说过 background-clip 属性,您可能会担心浏览器支持……好吧,别担心。background-clip 自 IE9 以来就一直存在!

此浏览器支持数据来自 Caniuse,其中提供了更多详细信息。数字表示浏览器在该版本及更高版本中支持该功能。

台式机

ChromeFirefoxIEEdgeSafari
1549127

移动设备/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
1271274.47.0-7.1

步骤 8:媒体查询!

大多数情况下,网格需要能够在它们增长和缩小时改变它们的列数。使用其他方法可能是非常痛苦的。你可能不得不计算一堆 nth-childs,以便你可以删除正确的边距或其他东西。使用这种方法,你只需要改变一个值!😃

.grid-cell {
  /* Sets the default column count */
  width: calc(100% / 1); /* 1 column */
}

@media (min-width: 400px){
  .grid-cell {
    width: calc(100% / 2); /* 2 columns */
  }
}

@media (min-width: 600px){
  .grid-cell {
    width: calc(100% / 3); /* 3 columns */
  }
}
3 x 2 网格,带间隙
2 x 3 网格,带间隙
1 x 6 网格,带间隙

这是我们将它们放在一起时的样子

查看 假网格,由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建。

没人有时间干这个!

与现代网格可以用三行 CSS 代码完成的工作相比,这已经很多了!为了简化任务,我创建了一个名为 Gutter Grid 的 SCSS 支持的混合器。一旦 Gutter Grid 安装到项目中,你就可以快速创建具有 20 像素间隙的三列网格,使用以下 SCSS 代码

.grid-wrapper {
  overflow: hidden; /* Need this for the chrome bug */
}

.grid {
  @include grid($cols: 3, $gutter: 20px);
}

如果这对你来说太冗长,你可以像这样写得更短

.grid-wrapper {
  overflow: hidden;
}

.grid {
  @include grid(3, 20px);
}

Gutter Grid 预先内置了一些断点集,因此如果你网格跨越整个页面,你可能根本不需要编写任何断点!但是,如果你确实需要自定义断点,那么 Gutter Grid 允许你像这样轻松地自定义它们

// Verbose custom breakpoints
@include grid($cols: 7, $gutter: 20px, $breakpoints: (
  4 : 960px, // At 960px or below, there will be 4 columns
  2 : (max, 600px), // You can use mq-scss syntax here as well
  1 : 480px,
));

// Short version  
@include grid(7, 20px, (
  4 : 960px,
  2 : 600px,
  1 : 480px,
));

你可能已经注意到,在示例中,Gutter Grid 也支持一个叫做 mq-scss 的东西使用的相同媒体查询语法。如果你想知道这是什么,那么它是一个我创建的 Sass 混合器,它使得编写和管理媒体查询变得容易很多。使用 mq-scss 语句来指示列数,可以对列数何时改变进行非常精细的控制。

向网格单元添加阴影

由于我们现在正在处理阴影,我将从示例图像中去除方框阴影。我们的起始网格现在看起来像这样

一个基本的 3 x 2 网格,带间隙和一个绿色边框围绕在外侧

如果我们现在尝试向每个网格单元添加一个外部 box-shadow……好吧,它看起来并不那么好

向网格单元添加阴影会导致阴影错位

让我们来修复它。

步骤 1:新的 HTML

为了创建漂亮的阴影,我们需要在每个网格单元中添加一个额外的 div。你不能真正为此使用 ::before::after,因为它们无法在其中包含 HTML 内容。



<div class="grid-wrapper">



<div class="grid">




<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>







<div class="grid-cell">



<div class="grid-cell-inner"></div>



</div>




</div>



</div>

步骤 2:使其灵活

现在,我们需要使每个网格单元成为一个 flex 容器。这将允许网格单元的内部部分占用其父级的全部高度。我们还需要将内部元素设置为 100% 的宽度。这将确保它水平和垂直地占用其父级的全部尺寸

.grid-cell {
  /* Forces inner to take up full grid cell height */
  display: flex;
}

.grid-cell-inner {
  /* Forces inner to take up full grid cell width */
  width: 100%;
}

让我们看看,如果我们尝试向内部元素添加方框阴影,我们会得到什么

.grid-cell-inner {
  box-shadow: 0 0 10px 3px blue;
}
方框阴影出现在网格单元周围,但被切断了

这很好看,但它还没有完全到位。我们用来防止 Chrome 错误的隐藏溢出正在妨碍。

步骤 3:hacky 填充

因此,我们需要允许溢出,但仍然避免这种奇怪的边距行为。我发现的唯一其他安全方法是使用填充。通过向外部网格包装器元素的顶部和底部添加 1 像素的填充,它将修复 Chrome 错误。

.grid-wrapper {
  /* Prevents odd margin behaviour in Chrome */
  padding: 1px 0;
}

这需要以在网格的顶部和底部增加 1 像素的空间为代价。下面的图片演示了最终的样子。阴影已经变淡,以便更清晰地显示 1 像素的间隙。

网格的顶部和底部有 1 像素的填充

**注意:**你可以通过选择不包含网格元素上的顶部填充间隙值来避免 1 像素的顶部填充。但 1 像素的底部填充无法避免。

应用到外部网格包装器的边框宽度也可以,所以从技术上讲,我不需要在上面的示例中应用填充。大多数情况下,如果我们向网格单元应用阴影,那么我们可能不想看到围绕它们的边框。上面的示例更多地是演示了填充是多么微小。

**更新:**你可以通过使用 0.1 像素的填充而不是 1 像素来完全避免奇怪的边距行为。这将在浏览器中被四舍五入到 0 像素,但仍然可以防止奇怪的边距行为发生。这意味着网格的边缘可以紧贴其容器的边缘,同时仍然允许溢出内容可见!感谢 Lu Nelson 在评论中 提出的建议!😁

这是没有外部边框的网格的样子

3 x 2 阴影单元网格
2 x 3 阴影单元网格
1 x 6 阴影单元网格

这里有一个演示最终产品的 Pen

查看 带有阴影的假网格,由 Daniel Tonon (@daniel-tonon) 在 CodePen 上创建。

Gutter Grid 阴影

让我们来了解如何在 Gutter Grid 单元中添加阴影。你可以使用与前一个示例中相同的 HTML 结构。

现在,应用此 SCSS 来创建一个具有 20 像素间隙的三列网格

.grid {
  @include grid(3, 20px, $inners: true);
}

这个新的 $inners: true 属性告诉 Gutter Grid,每个网格单元都有一个子元素,需要占用其父网格单元的全部高度和宽度。

不要使用 overflow: hidden,而是在包装器元素上使用 0.1 像素的底部填充(根据 Lu Nelson 的建议 更新)。

.grid-wrapper {
  padding-bottom: 0.1px;
}

如果 Gutter Grid 不需要,它不会输出一个顶部的外部间隙。这有助于避免负边距问题的出现。毕竟,如果没有一个负边距来抵消的顶部外部间隙,那么就没有需要担心的错误。但是,底部的外部间隙仍然是一个问题,这就是为什么我们需要 0.1 像素的底部填充。这 0.1 像素的底部填充将在浏览器中被四舍五入到 0 像素,同时仍然可以修复边距问题,导致网格底部没有间隙。

现在,添加你的阴影,你就拥有了一个带有阴影单元的 Gutter Grid!

.grid-cell-inner {
  box-shadow: 0 0 10px 3px blue;
}
3 x 2 阴影单元网格

在这篇文章中,我只简单介绍了 Gutter Grid 的功能。请务必阅读 完整文档,以了解它的其他功能。

我们的 IE 网格探险之旅即将结束

我希望你已经享受了这次对 IE 和 CSS 网格世界的探索。如果你还没有,请务必阅读 第一部分第二部分。阅读了所有三篇文章后,你将能够创建真正令人惊叹的布局,在 IE 中看起来和在现代浏览器中一样好。

如果你看到有人抱怨由于 IE 而无法使用 CSS 网格,你就知道该怎么做。用玩闹的方式拍拍他们的脑袋,因为他们太愚蠢了,然后把他们送到这里,让他们了解真相。

现在,我的朋友们,去创建一些网格吧!😃🎉

文章系列

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