练习动画最好的方式(SCSS篇):图片故障效果~

什么是故障效果?

它的原意是 “短暂的干扰”,在视觉艺术中常被用来指 “图像干扰”。 这是恐怖片和网络片中最常见的效果之一。

练习动画最好的方式(SCSS篇):图片故障效果~_第1张图片

什么是RGB置换?

色差、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,使其更容易写出随机的图像来制作动画。

将图像分割成RBG

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;
    }
  }
}

现在你应该能够看到红色通道。

练习动画最好的方式(SCSS篇):图片故障效果~_第2张图片

<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);
    ...
  }

RGB位移动画

@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位移动画。

练习动画最好的方式(SCSS篇):图片故障效果~_第3张图片

故障

如何实现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;
    }
  }
}

你可能感兴趣的:(前端,动画,scss,css)