如何不加任何元素就让图片有很炫酷的遮罩动画🔥

2,700 阅读6分钟

在本文中,将探索一些 CSS 技巧,可以为图像创建悬停动画来展示它们。let's go!

你可能会想:“嗯,这是个很简单的事情!在图像上面添加一个额外的元素进行动画,就完成了。”没错,但我们不会使用任何额外的元素或伪元素。我们将只使用 <img> 元素来完成。这听起来可能不可思议,因为仅使用图像元素,我们无法在其上方放置任何东西。事实上,确实不会在其上方放置任何东西,但会通过一些技巧进行隐藏! 废话不多说先直接看结果:

很酷,对吧?仅仅使用几行代码和没有额外元素就实现了一个预览动画。下面来剖析代码背后的魔力。

初始配置

首先定义一下图片的大小,这里面用到了我们前面提到的css自定义属性,可去这篇文章了解更多。CSS 中的自定义属性是什么?

img {
  --s: 200px; /* the image size */

  width: var(--s);
  height: var(--s);
  box-sizing: border-box;
}

到目前为止还没有太复杂的内容。为了简单起见,使用了一个正方形的图像,但实际上它可以是任意尺寸的图像。重要的是设置宽度和高度,而不是使用 aspect-ratio 属性或保留图像的默认大小。这对动画是必要的,稍后就知道为什么了。 另外使用了box-sizing: border-box,这也很重要。目前它并没有什么效果,继续下一步来了解为什么它是必需的。

设置padding

如果我们使用box-sizing: border-box来给固定尺寸的图片设置一些padding会发生什么呢,接下来让我们试一下。

通过上面演示可以看到设置了box-sizing:border-box后给右边图片设置padding-left: 100px会使图片压缩,我们可以看一下MDN对于box-sizing的定义:

  • border-box 告诉浏览器:你想要设置的边框和内边距的值是包含在 width 内的。也就是说,如果你将一个元素的 width 设为 100px,那么这 100px 会包含它的 border 和 padding,内容区的实际宽度是 width 减去 (border + padding) 的值。大多数情况下,这使得我们更容易地设定一个元素的宽高。

现在了解了元素内容是怎么填充的了,如果设置padding图片会被压缩,接下来演示鼠标悬停消失。

在上面的演示中,有两个特别需要注意的地方。第一,可以对 padding 进行动画处理,这很酷。第二,可以看到之前使用的 CSS 变量定义图像大小的重要性。使用相同的变量来定义 padding,这样就不必重复相同的值了。

添加背景颜色

以上面演示为例给它添加背景颜色。

现在加了背景颜色已经初见效果了,但是跟结果还是有一些不同,结果是覆盖内容在上,鼠标悬停显示图片,我们可以先设置padding-left让图片不可见,显示背景颜色,然后在hover时显示图片。

修改后可以看到离结果更近一步了。

添加object-fitobject-position

上面演示还存在的问题是图片会被压缩,可以使用object-fitobject-position来解决此问题,可以看一下MDN的解释:

object-fit 属性由下列的值中的单独一个关键字来指定。

取值

  • contain

被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比。整个对象在填充盒子的同时保留其长宽比,因此如果宽高比与框的宽高比不匹配,该对象将被添加“黑边"

  • cover

被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。

  • fill

被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。

  • none

被替换的内容将保持其原有的尺寸。

  • scale-down

内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。

这里我们用到的是cover这个属性。这里有两个重要的部分:

  1. "替换的内容被调整大小以保持其纵横比"。这意味着图像不会被压缩,而是保持其固有的纵横比。我们使用了一个正方形的图像,所以它将保持正方形。
  2. "填充元素的整个内容框...将被剪裁以适应"。图像应该填充整个内容区域(我们通过添加一些 padding 来减少的区域),但如果它无法适应,我们就会剪裁它。

这两部分确保了图像在保持纵横比的同时填充内容区域,如果图像太大无法适应,则会被剪裁。

接下来去尝试一下:

添加object-fit后可以看到图片已经不会被压缩了,但是图片的位置看起来会移动。所以接下来需要用object-position来固定图片的位置来让图片不在移动。

这样一个图片的遮罩动画就完成了,不需要使用任何的额外元素只通过简单的背景颜色以及一些定位技巧就可以实现。

可以通过调整填充方向就实现了开头不同方向的效果:

下面是用到的css:

img {
  --s: 200px; /* the image size */

  width: var(--s);
  height: var(--s);
  box-sizing: border-box;
  object-fit: cover;
  cursor: pointer;
  transition: .5s;
}

img.left {
  object-position: right;
  padding-left: var(--s);
  background: #542437;
}

img.right {
  object-position: left;
  padding-right: var(--s);
  background: #8A9B0F;
}

img.top {
  object-position: bottom;
  padding-top: var(--s);
  background: #E94E77;
}

img.bottom {
  object-position: top;
  padding-bottom: var(--s);
  background: #7A6A53;
}

img:hover {
  padding: 0;
}

更多的动画效果

可以是用同样的技巧扩展更多效果展示而不是单一的从一侧移入移出。

小结

通过object-fitobject-position这两个属性,还有我们提到的css自定义属性,再加上一些使用的小技巧可以不用任何外元素就实现精美的图片遮罩显示的动画效果。下面是最后一个演示。