在网格布局中缩放图像 PlatoBlockchain 数据智能。 垂直搜索。 哎。

在网格布局中缩放图像

多亏了 CSS Grid,创建图像网格很容易。 但是让网格做一些花哨的事情 after 已放置的图像可能很难完成。

假设您想在图像中添加一些花哨的悬停效果并放大它们所在的行和列? 我们能做到这一点!

很酷,对吧? 如果你检查代码,你不会发现任何 JavaScript、复杂的选择器,甚至 魔术数字. 这只是我们将要探索的众多例子中的一个!

构建网格

创建网格的 HTML 代码就像容器中的图像列表一样简单。 我们不需要更多。

<div class="gallery">
  <img>
  <img>
  <img>
  <!-- etc. -->
</div>

对于 CSS,我们首先使用以下设置网格:

.gallery {
  --s: 150px; /* controls the size */
  --g: 10px;  /* controls the gap */

  display: grid;
  gap: var(--g);
  width: calc(3*var(--s) + 2*var(--g)); /* 3 times the size plus 2 times the gap */
  aspect-ratio: 1;
  grid-template-columns: repeat(3, auto);
}

简而言之,我们有两个变量,一个控制图像的大小,一个设置图像之间的间隙大小。 aspect-ratio 有助于保持比例。

您可能想知道为什么我们只定义三列而不定义行。 不,我没有忘记行——我们只是不需要显式设置它们。 CSS Grid 能够自动将项目放置在 隐式行和列,这意味着我们可以获得任意数量的图像所需的行数。 我们可以显式定义行,但我们需要添加 grid-auto-flow: column 以确保浏览器将为我们创建所需的列。

这里有一个例子来说明这两种情况。 不同的是,一个流入一个 row 方向一个另一个 column 方向。

看一看 我写的另一篇文章 有关隐式网格和自动放置算法的更多信息。

现在我们有了网格,是时候为图像设置样式了:

.gallery > img {
  width: 0;
  height: 0;
  min-height: 100%;
  min-width: 100%;
  object-fit: cover;
}

我们制作的悬停效果依赖于这个 CSS。 您可能会觉得我们制作的图像既没有宽度也没有高度,但最小宽度和高度为 100%。 但是您会发现,对于我们正在努力实现的目标来说,这是一个非常巧妙的技巧。

我在这里做的是告诉浏览器图像需要有 0 宽度和高度,但还需要有一个最小高度等于 100%…但是 100% 什么? 使用百分比时,值为 相对于别的东西. 在这种情况下,我们的图像被放置在一个 网格单元 我们需要知道那个尺寸才能知道是什么 100% 是相对的。

浏览器会先忽略 min-height: 100% 计算网格单元的大小,但它将使用 height: 0 在其计算中。 这意味着我们的图像不会影响网格单元的大小……因为它们在技术上没有物理大小。 这将导致基于网格大小的三个相等的列和行(我们在 .gallery的宽度和 aspect-ratio)。 每个网格单元的高度不过是变量 --s 我们定义了(宽度相同)。

在网格布局中缩放图像

现在我们有了网格单元格的尺寸,浏览器将使用它 min-height: 100% (和 min-width: 100%) 这将强制图像完全填充每个网格单元的空间。 整个事情可能看起来有点混乱,但主要思想是确保网格定义图像的大小,而不是相反。 我不希望图像定义网格的大小,添加悬停效果后您会明白为什么。

创建悬停效果

我们需要做的是在图像悬停时增加图像的比例。 我们可以通过调整图像的 widthheight on :hover:

.gallery {
  --f: 1.5; /* controls the scale factor */
}

.gallery img:hover{
  width:  calc(var(--s) * var(--f));
  height: calc(var(--s) * var(--f));
}

我添加了一个新的自定义变量, --f,以混合作为比例因子来控制悬停时的大小。 注意我是如何乘以大小变量的, --s,通过它来计算新的图像大小。

但是你说图像大小需要为0。这是怎么回事? 我搞不清楚了…

我所说的仍然是正确的,但我对悬停的图像例外。 我告诉浏览器只有一个图像的大小不等于 XNUMX——因此它会影响网格的尺寸——而其他所有图像的大小都等于 0.

在网格布局中缩放图像 PlatoBlockchain 数据智能。 垂直搜索。 哎。
在网格布局中缩放图像

左侧显示了处于自然状态的网格,没有任何悬停的图像,这就是右侧显示的内容。 左侧的所有网格单元的大小都相同,因为所有图像都没有物理尺寸。

在右侧,第一行中的第二个图像被悬停,这为其提供了影响网格单元大小的尺寸。 浏览器将在悬停时使特定的网格单元格更大,这有助于整体大小。 并且由于设置了整个网格的大小(因为我们设置了一个固定的 width.gallery),其他网格单元将在逻辑上通过变小来响应,以保持 .gallery的整体大小机智。

这就是我们的缩放效果! 通过只增加一张图像的大小,我们会影响整个网格配置,我们之前说过,网格定义了图像的大小,以便每个图像在其网格单元内拉伸以填充所有空间。

为此,我们添加了一点 transition 并使用 object-fit 避免图像失真和错觉是完美的!

我知道这个伎俩背后的逻辑并不容易掌握。 如果您不完全理解它,请不要担心。 最重要的是了解所使用代码的结构以及如何修改它以获得更多变化。 这就是我们接下来要做的!

添加更多图像

我们创建了一个 3×3 的网格来解释主要技巧,但您可能已经猜到我们没有必要停在那里。 我们可以将列数和行数设为变量,并根据需要添加任意数量的图像。

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --s: 150px; /* control the size */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--s) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--s) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

我们有两个用于行数和列数的新变量。 然后我们只需使用它们定义网格的宽度和高度。 相同的 grid-template-columns 它使用的 --m 多变的。 和以前一样,我们不需要显式定义行,因为无论我们使用多少图像元素,CSS Grid 的自动放置功能都会为我们完成这项工作。

为什么不使用不同的宽度和高度值? 我们能做到这一点:

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --h: 120px; /* control the height */
  --w: 150px; /* control the width */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--w) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--h) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

.gallery img:hover{
  width:  calc(var(--w)*var(--f));
  height: calc(var(--h)*var(--f));
}

我们更换 --s 有两个变量,一个是宽度, --w,另一个是高度, --h. 然后我们相应地调整其他所有内容。

因此,我们从具有固定大小和元素数量的网格开始,但随后我们制作了一组新变量来获得我们想要的任何配置。 我们所要做的就是添加尽可能多的图像并相应地调整 CSS 变量。 组合是无限的!

全屏版呢? 是的,这也是可能的。 我们只需要知道我们需要为变量分配什么值。 如果我们想要 N 行的图像,我们希望我们的网格是全屏的,我们首先需要解决高度 100vh:

var(--n) * var(--h) + (var(--n) - 1) * var(--g) = 100vh

宽度的相同逻辑,但使用 vw 而不是 vh:

var(--m) * var(--w) + (var(--m) - 1) * var(--g) = 100vw

我们做数学得到:

--w: (100vw - (var(--m) - 1) * var(--g)) / var(--m)
--h: (100vh - (var(--n) - 1) * var(--g)) / var(--n)

完成!

它是完全相同的 HTML,但有一些更新的变量会改变网格的大小和行为。

请注意,我省略了我们之前设置的公式 .gallerywidthheight 并替换为 100vw100vh, 分别。 该公式将给我们相同的结果,但由于我们知道我们想要什么值,我们可以放弃所有增加的复杂性。

我们还可以简化 --h--w 通过消除等式中的差距来支持这一点:

--h: calc(100vh / var(--n)); /* Viewport height divided by number of rows */
--w: calc(100vw / var(--m)); /* Viewport width divided by number of columns */

这将使悬停的图像比上一个示例增长一点,但这没什么大不了的,因为我们可以使用 --f 我们用作乘数的变量。

由于变量在一个地方使用,我们仍然可以通过完全删除它们来简化代码:

请务必注意,此优化仅适用于全屏示例,而不适用于我们介绍的示例。 这个例子是一个特殊的例子,我们可以通过删除一些我们在其他例子中需要的复杂计算工作来使代码更轻。

实际上,我们拥有创建流行的扩展面板模式所需的一切:

让我们更深入地挖掘

你注意到我们的比例因子可以小于 1? 我们可以将悬停图像的大小定义为小于 --h or --w 但图像在悬停时变大。

初始网格单元大小等于 --w--h,那么为什么较小的值会使网格单元格 ? 细胞不应该得到 ,或者至少保持其初始大小? 网格单元的最终大小是多少?

我们需要更深入地研究 CSS Grid 算法如何计算网格单元格的大小。 这涉及到理解 CSS Grid 的默认值 拉伸对齐.

这是一个理解逻辑的例子。

在演示的左侧,我定义了一个两列 auto 宽度。 我们得到直观的结果:两个相等的列(和两个相等的网格单元)。 但是我在演示右侧设置的网格,我正在使用更新对齐 place-content: start,似乎什么都没有。

DevTools 有助于向我们展示这两种情况下的真实情况:

在网格布局中缩放图像 PlatoBlockchain 数据智能。 垂直搜索。 哎。
在网格布局中缩放图像

在第二个网格中,我们有两列,但它们的宽度为零,因此我们得到两个网格单元格,它们折叠在网格容器的左上角。 这是 不能 一个错误,但网格对齐的逻辑结果。 当我们用 auto,这意味着它的内容决定了它的大小——但我们有一个空的 div 没有内容可以腾出空间。

但是由于 stretch 是默认对齐方式,并且我们在网格内有足够的空间,浏览器将平均拉伸两个网格单元以覆盖所有区域。 这就是左边的网格以两个相等的列结束的方式。

规范:

请注意,某些值 justify-contentalign-content 可能会导致轨道分开(space-around, space-between, space-evenly) 或调整大小 (stretch).

请注意“要调整大小”,这是这里的关键。 在最后一个示例中,我使用了 place-content 这是简写 justify-contentalign-content

这被埋在某处 网格大小算法 眼镜:

此步骤扩展具有 汽车 最大轨道尺寸功能 通过除以任何剩余的积极, 可用空间 在他们中间。 如果空闲空间是 不定,但 网格容器 有确定的 最小宽度/高度,而是使用该大小来计算此步骤的可用空间。

“平等”解释了为什么我们以平等的网格单元结束,但它适用于非常重要的“自由空间”。

让我们以前面的示例为例,将内容添加到其中一个 divs:

我们添加了一个正方形 50px 图片。 这是我们示例中每个网格如何响应该图像的说明:

在网格布局中缩放图像 PlatoBlockchain 数据智能。 垂直搜索。 哎。
在网格布局中缩放图像

在第一种情况下,我们可以看到第一个单元格(红色)大于第二个单元格(蓝色)。 在第二种情况下,第一个单元格的大小发生变化以适应图像的物理大小,而第二个单元格保持没有尺寸。 空闲空间被平均分配,但第一个单元格内部的内容更多,这使得它更大。

这是计算我们的可用空间的数学:

(grid width) - (gap) - (image width) = (free space)
200px - 5px - 50px = 145px 

除以二 - 列数 - 我们得到宽度 72.5px 对于每一列。 但是我们加上图片的大小, 50px, 到第一列,它给我们留下一列 122.5px 第二个等于 72.5px.

同样的逻辑也适用于我们的图像网格。 所有图像的大小等于 0 (无内容)而悬停的图像有助于大小 - 即使它只是 1px - 使其网格单元比其他网格单元更大。 因此,比例因子可以是任何大于 0 甚至小数之间 01.

为了得到网格单元格的最终宽度,我们做同样的计算得到以下结果:

(container width) - (sum of all gaps) - (hovered image width) = (free space)

容器的宽度定义为:

var(--m)*var(--w) + (var(--m) - 1)*var(--g)

…所有的差距都等于:

(var(--m) - 1)*var(--g)

…对于悬停的图像,我们有:

var(--w)*var(--f)

我们可以用我们的变量计算所有这些:

var(--m)*var(--w) - var(--w)*var(--f) = var(--w)*(var(--m) - var(--f))

列数定义为 --m ,所以我们平均分配空闲空间以获得:

var(--w)*(var(--m) - var(--f))/var(--m)

…这给了我们非悬停图像的大小。 对于悬停的图像,我们有这个:

var(--w)*(var(--m) - var(--f))/var(--m) + var(--w)*var(--f)
var(--w)*((var(--m) - var(--f))/var(--m) + var(--f))

如果我们想控制悬停图像的最终大小,我们考虑上面的公式来得到我们想要的确切大小。 例如,如果我们希望图像是两倍大:

(var(--m) - var(--f))/var(--m) + var(--f) = 2

所以,我们的规模乘数的值, --f, 需要等于:

var(--m)/(var(--m) - 1)

对于三列,我们将有 3/2 = 1.5 这就是我在本文第一个演示中使用的比例因子,因为我想让图像在悬停时放大两倍!

相同的逻辑适用于高度计算,如果我们想独立控制它们,我们需要考虑两个比例因子以确保悬停时具有特定的宽度和高度。

.gallery {
  /* same as before */
   --fw: 1.5; /* controls the scale factor for the width */
   --fh: 1.2; /* controls the scale factor for the height */

  /* same as before */
}

.gallery img:hover{
  width:  calc(var(--w)*var(--fw));
  height: calc(var(--h)*var(--fh));
}

现在,您知道了创建具有酷悬停效果的任何类型图像网格的所有秘密,同时还可以使用我们刚刚介绍的数学来控制您想要的大小。

结束了

在我 上篇文章,我们用几行 CSS 创建了一个外观复杂的网格,使用了 CSS Grid 的隐式网格和自动放置功能。 在本文中,我们依靠一些 CSS 网格大小技巧来创建一个精美的图像网格,这些图像在悬停时放大并导致网格相应地调整。 所有这一切都通过使用 CSS 变量轻松调整的简化代码实现!

在下一篇文章中,我们将玩形状! 我们将 CSS 网格与蒙版和剪辑路径结合起来,以获得精美的图像网格。

时间戳记:

更多来自 CSS技巧