纯CSS图片碎裂动画教程
前言
最近看到一篇文章是关于css做图片销毁图片效果的,觉得不错,就给大家翻译过来分享一下,原文地址:传送门
文章开始,先来通过GIF动图展示一下最后的开发成果。没有JavaScript处理,没有SVG。只使用单个<img>
和一些CSS渲染。当我们将鼠标悬停在图片上,即可看到魔法效果。
是不是很酷?好吧,我不得不承认这不仅是CSS,因为还有SCSS,但是它仍然算是纯CSS效果,但没有涉及JS。
上述效果包含两个过程。
- 蒙版
- 动画渐变
蒙版
蒙版有时很难概念化,并且常常与剪切相混淆。最重要的是:蒙版是图像。当将图像用作蒙版应用于元素时,图像的任何透明部分都允许我们直接通过元素看到。任何不透明的部分都会使元素完全可见。
蒙版的工作方式与不透明度(opacity
)相同,只是它们作用在同一个元素的不同部分上。这与剪切不同,剪切是将路径之外的所有内容都隐藏起来的路径。蒙版的优点在于,在同一个元素上可以具有任意数量的图层蒙版——与在background-image
上链接多个图像的方式类似。
下面举一个简单的例子以便于更好地理解这一技巧(左边是原图,右边是加入蒙版的)
.img-mask {
mask: linear-gradient(rgba(0, 0, 0, 0.8) 0 0) left, linear-gradient(rgba(0, 0, 0, 0.5) 0 0) right;
mask-size: 50% 100%;
mask-repeat: no-repeat;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style/style.css">
</head>
<body>
<img src="https://gitee.com/kevinlu98/imgbed/raw/master/20220124/7W95aI3HC0hv.png" alt="">
<img class="img-mask" src="https://gitee.com/kevinlu98/imgbed/raw/master/20220124/7W95aI3HC0hv.png" alt="">
</body>
</html>
我们在图像上定义了两个图层蒙版,都是纯色的,但是alpha
透明度值不同。
值得注意的是,使用何种颜色无关紧要,因为默认的mask-mode
为alpha
。唯一有重大关系的就是alpha
值。渐变可以是linear-gradient(rgba(X,Y,Z,0.8) 0 0)
,其中X
,Y
和Z
都是随机值。
每个图层蒙版尺寸为50% 100%
(或图像的一半宽度和全部高度)。一个图层蒙版覆盖左侧,另一个覆盖右侧。然后,我们得到了两个不重叠的蒙版,它们覆盖了图像的整个区域,并且正如我们前面所说,每个蒙版定义的alpha
透明度值不同。
动画渐变
我们要做的是将动画应用于蒙版的线性渐变alpha
值,以创建透明动画。稍后,我们再将它们制作成异步动画,以创建碎片效果。
动画渐变是我们在CSS中无法做到的。但是,现在我们有@property
的支持,尽管支持是有限的。
简而言之,@property
允许我们创建自定义的CSS属性,其中我们可以通过指定类型来定义语法。下面让我们创建两个属性--c-0
和--c-1
,初始值为1
。
@property --c-0 {
syntax: "<number>";
initial-value: 1;
inherits: false;
}
@property --c-1 {
syntax: "<number>";
initial-value: 1;
inherits: false;
}
这些属性将代表CSS蒙版中的alpha
值。并且由于它们都默认为完全不透明的(因为值为1),因此整个图像会通过蒙版显示。下面是我们如何使用自定义属性重写蒙版的方法:
.img-mask {
-webkit-mask: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(0, 0, 0, var(--c-0)))) left, -webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(0, 0, 0, var(--c-1)))) right;
-webkit-mask: linear-gradient(rgba(0, 0, 0, var(--c-0)) 0 0) left, linear-gradient(rgba(0, 0, 0, var(--c-1)) 0 0) right;
mask: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(0, 0, 0, var(--c-0)))) left, -webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(0, 0, 0, var(--c-1)))) right;
mask: linear-gradient(rgba(0, 0, 0, var(--c-0)) 0 0) left, linear-gradient(rgba(0, 0, 0, var(--c-1)) 0 0) right;
-webkit-mask-size: 50% 100%;
mask-size: 50% 100%;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
transition: --c-0 0.5s, --c-1 0.3s 0.4s;
}
.img-mask:hover {
--c-0: 0;
--c-1: 0;
}
我们在此所做的就是为每个自定义变量应用不同的过渡持续时间和延迟。接下来我们继续来实现鼠标悬停在图像上的效果。蒙版的第一个渐变将逐渐淡出,直到alpha
值为0,以使图像完全透明,然后是第二个渐变。
更多蒙版
到目前为止,我们仅在蒙版上使用了两个线性渐变,也仅处理了两个自定义属性。要创建碎片效果,这是不够的,也就是意味着需要更多的渐变和自定义属性!
SCSS让这项工作变得相当琐碎,因此现在我们要开始编写样式。如我们在第一个示例中看到的,我们有一种拼接矩阵。我们可以将它们视为行和列,因此可以定义两个SCSS变量$x
和$y
来表示。
定义属性
每个属性都需要有@property
定义。但是,没有人希望去手写完成这些内容,因此不妨使用SCSS通过循环运行属性来为我们完成这个繁重的工作:
@for $i from 0 through ($x - 1) {
@for $j from 0 through ($y - 1) {
@property --c-#{$i}-#{$j} {
syntax: "<number>";
initial-value: 1;
inherits: false;
}
}
}
渐变
我们打算编写@mixin
为我们生成渐变:
@mixin image() {
$all_t: (); // Transition
$all_m: (); // Mask
@for $i from 0 through ($x - 1) {
@for $j from 0 through ($y - 1) {
$all_t: append($all_t, --c-#{$i}-#{$j} transition($i,$j), comma);
$all_m: append($all_m, linear-gradient(rgba(0,0,0,var(--c-#{$i}-#{$j})) 0 0) calc(#{$i}*100%/(#{$x} - 1)) calc(#{$j}*100%/(#{$y} - 1)), comma);
}
}
transition: $all_t;
mask: $all_m;
}
我们所有的图层蒙版大小均等,因此我们只需要一个属性,它依赖于$x
和$y
变量以及calc()
:
mask-size: calc(100%/#{$x}) calc(100%/#{$y})
你可能也注意到了这行代码:
$all_t: append($all_t, --c-#{$i}-#{$j} transition($i,$j), comma);
我们还将生成过渡属性,过渡属性包含所有先前定义的自定义属性。
最后,得益于SCSS中的random()
函数,为每个属性生成了不同的持续时间/延迟。
@function transition($i,$j) {
@return $s*random()+s $s*random()+s;
}
现在,我们要做的就是调整$x
和$y
变量,以控制碎片的粒度。
我们可以扩展代码并更改随机配置,以考虑不同种类的动画。
结束语
所有我们要做的是找到变量和公式之间的完美组合,就可以创建令人惊讶的超炫酷的图像碎片效果。
52Hz 游客 2022-01-27 23:25 回复
做的挺好的,那可不可以添加别的效果呢?(比如把方块碎裂换成圆点)
D 游客 2022-01-24 19:51 回复
还可以啊