用CSS网格定位叠加内容

252 阅读10分钟

对于2021年的任何网络开发者来说,这不是新闻。CSS网格是一个非常强大的工具,用于创建复杂、独特的二维现代网页布局。

最近,我一直在尝试使用CSS网格和对齐属性来创建包含多个重叠元素的组件布局。这些布局可以使用绝对定位和混合的偏移值(top,right,bottom,left )、负边距和变换来进行造型。但是,通过CSS Grid,可以使用更有逻辑性、可读性的属性和值来构建定位叠加元素。下面是这些网格属性派上用场的几个例子。

阅读以下内容会有所帮助 [grid-template-areas](https://css-tricks.com/snippets/css/complete-guide-grid/#prop-grid-template-areas)[grid-area](https://css-tricks.com/snippets/css/complete-guide-grid/#grid-area)属性,如果你对它们还不熟悉的话。

在有限的尺寸内展开图像

CodePen 嵌入回退

在演示中,有一个复选框可以切换溢出的可见性,这样我们就可以看到图像尺寸在较大的视口宽度上扩展到容器之外的地方。

这里是一个常见的英雄部分,其标题与图像重叠。虽然图片的上限是max-width ,但它在桌面上的尺寸却相当高。正因为如此,内容策略团队要求英雄下面的一些相关页面内容在视口中尽量保持可见。结合这种布局技术和使用CSSclamp() 函数的流体容器max-height ,我们可以开发出一种基于可用视口空间的调整,同时将英雄图像固定在容器的中心。

CSSclamp() ,以及min()max() 比较函数,在所有现代浏览器中都得到很好的支持。没用过它们?艾哈迈德-沙迪德在这篇文章中进行了精彩的深入研究。

打开这个笔,调整视口的宽度。根据图片的尺寸,容器的高度会扩大,直到达到最大高度。注意,图像继续增长,同时保持在容器的中心位置。调整视口的高度,容器将在max-height's lower and upper bound values defined in theclamp() function之间弯曲。

在使用网格布局样式之前,我可能会尝试对图片和标题进行绝对定位,使用长宽比填充技巧来创建一个响应的高度,以及object-fit 来保留图片的比例。像这样的东西可以让它达到目的。

.container {
  position: relative;
  max-height: clamp(400px, 50vh, 600px);
}

.container::before {
  content: '';
  display: block;
  padding-top: 52.25%;
}

.container > * {
  max-width: 1000px;
}

.container .image {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.container .title {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  text-align: center;
}

也许可以把代码缩减一些,但仍然需要大量的样式设计。用CSS Grid管理同样的响应式布局,将简化这些布局样式规则,同时使代码更易读。在下面的迭代中可以看到。

.container {
  display: grid;
  grid-template: "container";
  place-items: center;
  place-content: center;
  overflow: hidden;
  max-height: clamp(450px, 50vh, 600px);
}

.container > * {
  grid-area: container;
  max-width: 1000px;
}

place-content: center 指示图片继续从容器的中间长出来。删除这一行,可以看到,虽然通过 ,图像仍然垂直居中,但一旦达到 ,图像将粘在容器块的顶部,并继续扩展到其底部以外。设置 ,你会看到图像溢出到容器的顶部。place-items max-height place-content: end center

这种行为在概念上似乎类似于在图像上应用object-fit: cover ,作为一种风格化的方法,在调整大小以填充其内容框尺寸时,保留其固有的比例(它在绝对位置迭代中被利用)。然而,在这个网格上下文中,图像元素控制着它的父元素的高度,一旦达到父元素的max-height ,图像就会继续扩展,保持其比例,如果父元素溢出,就会保持完全可见。object-fit 甚至可以在这里与aspect-ratio 属性一起使用,为英雄图像创建一个一致的长宽比模式。

.container .image {
  width: 100%;
  height: auto;
  object-fit: cover;
  aspect-ratio: 16 / 9;
}

叠加grid-area

接着是容器的直接子代,grid-area ,安排每个子代,使它们重叠在同一空间。在这个例子中,grid-template-areas ,用命名的网格区域使代码更易读,作为组件库中其他叠加式布局的模式,效果也很好。也就是说,通过删除模板规则和使用整数代替grid-area: container ,也可以得到同样的结果。

.container > * {
  grid-area: 1 / 1;
}

这是对grid-row-start,grid-column-start,grid-row-end, 和grid-column-end 的简写。由于这个演示中的兄弟姐妹都共享相同的单行/单列区域,因此只需要设置起始行就可以得到所需的结果。

设置place-self 来放置自己

另一种常见的叠加模式可以在图片旋转木马上看到。交互式元素经常被放置在旋转木马视口的顶部。我对第一个演示进行了扩展,用旋转木马取代了静态的英雄图像。

CodePen嵌入回退

和之前的故事一样。这个布局可以退回到绝对定位,并在少数属性中使用整数值来推动和拉动元素围绕它们的父容器。相反,我们将重新使用前一个演示中的网格布局规则集。一旦应用,它就会像你所期望的那样出现:所有的子元素都在容器内居中,相互叠加。

Picture of a cute light brown puppy with the words Welcome to the Snuggle Zone on top in white. The text overlaps over text elements and is hard to read.

通过在容器上声明place-items: center ,它的所有直接子元素都会相互重叠。

下一步是在各个元素上设置对齐值。符号 [place-self](https://css-tricks.com/almanac/properties/p/place-self/)属性是align-selfjustify-self的缩写,它提供了对容器内单个项目位置的细化控制。下面是全部的布局样式。

.container {
  display: grid;
  grid-template:"container";
  place-items: center;
  place-content: center;
  overflow: hidden;
  max-height: clamp(450px, 50vh, 600px);
}

.container > * {
  grid-area: container;
  max-width: 1000px;
}

.title {
  place-self: start center;
}

.carousel-control.prev {
  place-self: center left;
}

.carousel-control.next {
  place-self: center right;
}

.carousel-dots {
  place-self: end center;
}

只有一个小问题:当图像超过容器的尺寸时,标题和旋转木马的圆点指示器会被拉出到溢出部分。

为了正确地将这些元素包含在父代中,grid-template-row 值需要是容器的100%,这里设置为一个小数单位。

.container {
  grid-template-areas: "container";
  grid-template-rows: 1fr;
}

在这个演示中,我倾向于使用grid-template 这个缩写(我们将在本文后面再次看到这个缩写)。

.container {
  grid-template: "container" 1fr;
}

在提供了这个小小的更新后,即使旋转木马的图像扩散到旋转木马的边界之外,覆盖元素也会留在父容器内。

对齐和命名grid-template-areas

让我们再用前面的叠加布局方法来举一个例子。在这个演示中,每个盒子包含的元素被定位在图像上面的不同区域。

CodePen嵌入回退

对于第一次迭代,一个命名的模板区域被声明为在父元素空间上叠加子元素,与之前的演示类似。

.box {
  display: grid;
  grid-template-areas: "box";
}

.box > *,
.box::before {
  grid-area: box;
}

现在图像和半透明的覆盖物覆盖了盒子区域,但这些样式规则也将其他项目延伸到整个空间。这似乎是一个合适的时机,place-self ,给这些元素加上一些对齐的魔法!

.tag {
  place-self: start;
}

.title {
  place-self: center;
}

.tagline {
  place-self: end start;
}

.actions {
  place-self: end;
}

这看起来很好!每一个元素都按照预定的位置被放置在图片上的规定位置。嗯,差不多。在标语和行动按钮所在的底部区域有一点细微的差别。将鼠标悬停在图片上,可以看到标语。在桌面屏幕上,这可能看起来很好,但如果标语变长(或视口中的盒子变小),它最终会延伸到行动按钮后面。

A two by two grid of images with text overlaid on top, as well as a tag label in the top right corner and, tagline in the bottom left corner and actions to like and share in the bottom right corner of each one.

请注意第二行第一个方框中的标语是如何与行动按钮重叠的。

为了清理这个问题,grid-template-areas ,为标语和动作使用命名的区域。grid-template-columns 规则的引入,使动作容器的大小仅能适应其按钮的大小,而标语则使用1fr 值来填充内联区域的其余部分。

.box {
  display: grid;
  grid-template-areas: "tagline actions";
  grid-template-columns: 1fr auto;
}

这也可以与grid-template 速记相结合。列值在斜线后定义,像这样。

.box {
  grid-template: "tagline actions" / 1fr auto;
}

grid-area ,然后转换为整数,现在 "box "关键字已被删除。

.box > *,
.box::before {
  grid-area: 1 / 1 / -1 / -1;
}

一切都应该和以前一样了。现在进行最后的修饰。taglineactions 关键字被设置为各自的元素grid-area 值。

.tagline {
  grid-area: tagline;
  place-self: end start;
}

.actions {
  grid-area: actions;
  place-self: end;
}

现在,当把鼠标悬停在演示中的卡片上时,当文本变得太长时,标语会被包裹成多行,而不是像以前那样推过动作按钮。

命名的网格线

回顾这段代码的第一次迭代,我非常喜欢将默认的grid-area 设置为box 关键字。有一种方法可以把它找回来。

我将在模板中添加一些命名的网格线。在下面的grid-template 规则中,第一行定义了命名的模板区域,这也代表了行。斜线之后是明确的列尺寸(为了便于阅读,移到了新的一行)。[box-start][box-end] 自定义标识符代表box 区域。

.box {
  display: grid;
  grid-template: 
    [box-start] "tagline actions" [box-end] /
    [box-start] 1fr auto [box-end];
}

.box > *,
.box::before {
  grid-area: box;
}

将一个带有-start-end 语法的名称传入括号中,为该名称定义了一个区域。这个名字被称为自定义标识符,可以是任何东西,但应避免使用CSS规范中的词语

逻辑放置值

在这最后一个例子中,真正值得观察的部分是使用逻辑值,如startend ,来放置元素。如果directionwriting-mode 发生变化,那么这些元素将相应地重新定位。

当从下拉菜单中选择 "从右到左 "的方向时,内联的开始和结束位置就会颠倒。这种布局可以适应从右向左阅读的语言,如阿拉伯语或希伯来语,而不必覆盖任何现有的CSS。

总结

我希望你喜欢这些演示,并为你自己的项目布局提供一些新的想法--我已经汇编了一个例子集,你可以在CodePen上查看一下。CSS网格规范所包含的力量是不可思议的。花一分钟思考一下使用浮点clearfix进行原始网格行设计的日子,然后回到今天,看看今天的CSS的辉煌的布局和显示属性。要让这些东西很好地工作并不容易,所以让我们为CSS工作小组的成员鼓掌。网络空间在继续发展,他们继续使它成为一个有趣的构建场所。

现在让我们发布容器查询,让这个派对真正开始。


用CSS网格定位叠加内容》首先出现在CSS-Tricks上。你可以通过成为MVP支持者来支持CSS-Tricks。