它的原意是 “短暂的干扰”,在视觉艺术中常被用来指 “图像干扰”。 这是恐怖片和网络片中最常见的效果之一。
色差、RGB偏移、RGB分裂(RGB split)等。有各种方法来描述它,但从本质上讲,它意味着光的三原色,即红、绿、蓝,在没有任何错位的情况下应该重叠显示的状态。
这是与突变效果一起使用的,在某些情况下,突变一词被用来包括颜色的转变,所以在这种情况下也实施它,会产生更多的突变效果。
HTML:
<div class="glitch" style="background-image: url(...);">
div>
在元素的内联样式中指定你想要突变的图像作为背景图像
我们使用background-image是为了避免在将图像分割成RGB时多次写入图像的URL,虽然我们可以在CSS中指定背景图像,但我们使用了内联样式,使之更容易在HTML中改变图像。
CSS:
.glitch {
background: #000 no-repeat center;
background-size: 0; // `.glitch` 不要在自身上显示背景图像
height: 100vh;
overflow: hidden;
position: relative;
}
这是我们的CSS代码,关键是background-size: 0;这意味着.glitch元素本身并不显示图像。
原始的CSS当然也可以,但我们将使用Sass,使其更容易写出随机的图像来制作动画。
html:
<div class="glitch" style="background-image: url(...);">
<div class="channel r">div>
div>
现在让我们试试只显示红色通道。
.glitch {
...
.channel {
background: inherit; // 继承容器元素的背景
background-size: cover;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
// 与上面的".channel "分开,以便以后执行。
.channel {
&::before {
bottom: 0;
content: "";
display: block;
left: 0;
mix-blend-mode: multiply; // 将图像乘以R/G/B来创建各自的通道
position: absolute;
right: 0;
top: 0;
}
}
.r {
&::before {
background: #f00;
}
}
}
现在你应该能够看到红色通道。
<div class="glitch" style="background-image: url(...);">
<div class="channel r">div>
<div class="channel g">div>
<div class="channel b">div>
div>
同样的,添加绿色和蓝色通道。
.glitch {
...
.channel {
...
}
.channel {
mix-blend-mode: screen; // 每个通道都可以通过在屏幕上的重叠与原始图像相结合
&::before {
...
}
}
.r {
...
}
.g {
&::before {
background: #0f0;
}
}
.b {
&::before {
background: #00f;
}
}
创建每个RGB通道并在屏幕上叠加,以显示原始图像。
然后你可以对通道进行平移(),以获得RGB位移效果。
.r {
transform: translate(4px, 2px);
...
}
.g {
transform: translate(-3px, -1px);
...
}
@function rand($min, $max) {
@return random() * ($max - $min) + $min;
}
我们将创建一个随机函数,使我们能够轻松地设置最大和最小值。
$animation-duration: 3s; // 循环播放动画的时间为多少秒
$glitch-duration: 20%; // 突变(RGB位移)本身的长度,占上述秒数的百分比
$glitch-frequency: 10; // 运动频率
$glitch-interval: $glitch-duration / $glitch-frequency;
@mixin rgb-shift($name) {
@keyframes rgb-shift-#{$name} {
@for $i from 0 to $glitch-frequency {
#{$i * $glitch-interval} {
transform: translate(
#{rand(-2, 2) * 1%}, // 它向左或向右移动的程度(宽度的±2%)。
#{rand(-0.5, 0.5) * 1%} // 上下移动的程度(高度的±0.5%)。
);
}
}
#{$glitch-duration}, 100% {
transform: none;
}
}
animation: rgb-shift-#{$name} $animation-duration steps(1, jump-end) infinite alternate both;
}
为每个RGB通道创建一个混合器,同时创建@keyframes并设置动画。
@use 'sass:math';
@function rand($min, $max) {
@return math.random() * ($max - $min) + $min;
}
$glitch-interval: math.div($glitch-duration, $glitch-frequency);
最新版本的Sass推荐使用上述数学函数,但其中一些函数不被CodePen所支持,所以我们将全程使用一个稍微传统的方法。
重点是,动画定时函数应该使用step(n,
)函数,使运动更加突兀,因为它将是生硬的而不是平滑的。
另一件事是,动画方向被设置为交替进行。你可以通过调整$animation-duration
$glitch-duration
$glitch-frequency
来做到没有它,但如果你把它设置为交替,重复的动画将是上图的一半,即使它有同样的glitch长度和静态状态。 如上图所示,同样长度的故障和停顿,交替进行的时间减半。 如上图所示,同样长度的突变和静止,需要重复动画的一半,因此需要编写一半的CSS代码。
.r {
transform: translate(4px, 2px);
@include rgb-shift(r);
...
}
.g {
transform: translate(-3px, -1px);
@include rgb-shift(g);
...
}
.b {
@include rgb-shift(b);
...
}
在每个通道中包括一个混合器来播放RGB位移动画。
如何实现glitching,就是将同一张图片重叠,剪掉一部分,然后转移。
.glitch {
...
&::before,
&::after,
.channel {
background: inherit;
background-size: cover;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
&::before {
content: "";
}
&::after {
content: "";
}
...
}
使用一个伪元素来分层相同的图像(例如,一个div)。
.glitch {
...
&::before {
clip-path: polygon(
0 20%,
100% 20%,
100% 30%,
0 30%
);
transform: translate(5%, 0.5%);
content: "";
}
&::after {
clip-path: polygon(
0 60%,
100% 60%,
100% 65%,
0 65%
);
transform: translate(-5%, -0.5%);
content: "";
}
...
}
让我们尝试在静态状态下显示故障。 使用clip-path()来裁剪图像。
之前的是在RGB层下面,而RGB层有mix-blend-mode: sreen;
,所以只有那部分的图像比较亮,我觉得这是很突兀的。
后面的就比较难看了,但在中间稍下方有一小部分图像稍微有点不对劲。
这只是两张图片,但如果你经常移动它们并调整它们的大小,再加上RGB位移,就会出现相当多的故障。 当然,你可以通过使用div等添加更多内容。
@mixin glitch($name) {
@keyframes glitch-#{$name} {
@for $i from 0 to $glitch-frequency {
$left: 0%;
$right: 100%;
$top: rand(0, 90) * 1%;
$bottom: $top + rand(1, 10) * 1%;
#{$i * $glitch-interval} {
clip-path: polygon(
$left $top,
$right $top,
$right $bottom,
$left $bottom
);
transform: translate(
#{rand(-8, 8) * 1%},
#{rand(-0.5, 0.5) * 1%}
);
}
}
#{$glitch-duration}, 100% {
clip-path: none;
transform: none;
}
}
animation: glitch-#{$name} $animation-duration linear infinite alternate both;
}
与RGB置换一样,创建了一个混杂物。
.glitch {
...
&::before {
@include glitch(before);
clip-path: polygon(
0 20%,
100% 20%,
100% 30%,
0 30%
);
transform: translate(5%, 0.5%);
content: "";
}
&::after {
@include glitch(after);
clip-path: polygon(
0 60%,
100% 60%,
100% 65%,
0 65%
);
transform: translate(-5%, -0.5%);
content: "";
}
...
}
你所要做的就是把它包含在伪元素中,然后你就完成了。
如果你像演示中那样无限循环地制作动画,可能会让观众感到不舒服,所以你可能要考虑剂量问题。 然而,你可以使用CSS来应用突变和RGB位移效果,这意味着你可以很容易地将其作为鼠标悬停效果。
<div class="glitch" style="background-image: url(https://images.hdqwalls.com/wallpapers/rolls-royce-black-badge-ghost-2021-4k-cd.jpg);">
<div class="channel r">div>
<div class="channel g">div>
<div class="channel b">div>
div>
@function rand($min, $max) {
@return random() * ($max - $min) + $min;
}
$animation-duration: 3s;
$glitch-duration: 20%;
$glitch-frequency: 10;
$glitch-interval: $glitch-duration / $glitch-frequency;
@mixin rgb-shift($name) {
@keyframes rgb-shift-#{$name} {
@for $i from 0 to $glitch-frequency {
#{$i * $glitch-interval} {
transform: translate(
#{rand(-2, 2) * 1%},
#{rand(-0.5, 0.5) * 1%}
);
}
}
#{$glitch-duration}, 100% {
transform: none;
}
}
animation: rgb-shift-#{$name} $animation-duration steps(1, jump-end) infinite alternate both;
}
@mixin glitch($name) {
@keyframes glitch-#{$name} {
@for $i from 0 to $glitch-frequency {
$left: 0%;
$right: 100%;
$top: rand(0, 90) * 1%;
$bottom: $top + rand(1, 10) * 1%;
#{$i * $glitch-interval} {
clip-path: polygon(
$left $top,
$right $top,
$right $bottom,
$left $bottom
);
transform: translate(
#{rand(-8, 8) * 1%},
#{rand(-0.5, 0.5) * 1%}
);
}
}
#{$glitch-duration}, 100% {
clip-path: none;
transform: none;
}
}
animation: glitch-#{$name} $animation-duration linear infinite alternate both;
}
body {
margin: 0;
}
.glitch {
background: #000 no-repeat center;
background-size: 0;
height: 100vh;
position: relative;
overflow: hidden;
&::before,
&::after,
.channel {
background: inherit;
background-size: cover;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
&::before {
@include glitch(before);
content: "";
}
&::after {
@include glitch(after);
content: "";
}
.channel {
mix-blend-mode: screen;
&::before {
bottom: 0;
content: "";
display: block;
mix-blend-mode: multiply;
position: absolute;
left: 0;
right: 0;
top: 0;
}
}
.r {
@include rgb-shift(r);
&::before {
background: #f00;
}
}
.g {
@include rgb-shift(g);
&::before {
background: #0f0;
}
}
.b {
@include rgb-shift(b);
&::before {
background: #00f;
}
}
}