文本/图像/SVG 的故障效果

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

Lucas Bebber 的 故障 是一种超级酷炫的效果。就像您正在查看以逐行扫描显示器显示的某些文本,该显示器已多次掉落在地板上,因此像素的对齐方式在时间和空间上以奇怪的不均匀量偏移。

如果曾经有过,它就是货真价实的 CSS 技巧!我花了一段时间才弄清楚它是如何工作的,所以我想我会解释一下。然后我最终使其也适用于其他类型的內容,并将其制作成一组 Sass @mixin,以便更轻松地使用它。

查看 CodePen 上 Chris Coyier (@chriscoyier) 编写的
CSS 故障文本

CodePen 上。

文本的三个副本

虽然 HTML 只是

<div class="glitch" data-text="GLITCH">GLITCH</div> 

通过伪元素创建了它的三个副本,并且它们彼此重叠放置。

.glitch {
  position: relative;
}
.glitch::before,
.glitch::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

生成三个可以单独控制的唯一副本

更改副本

每个副本都相同,除了

  • 它向左或向右偏移
  • 它有一个突出显示,以文本阴影的形式显示

在偏移和突出显示之间,它给它一种断裂的感觉。

.glitch::before {
  /* ... anything needed to make it identical */

  /* variation */
  left: 2px;
  text-shadow: -1px 0 red;
  
  /* important: opaque background masks the original */
  background: black;
}
.glitch::after {
  /* ... anything needed to make it identical */

  /* variation */
  left: -2px;
  text-shadow: -1px 0 blue;
  
  /* important: opaque background masks the original */
  background: black;
}

所以现在这三个副本是这样的

裁剪副本

如果保持原样,您只会看到最顶层的副本。可能是 ::after 版本,除非您使用 z-index 进行更改。但不用担心,我们将只使用 clip 属性 显示顶部已更改副本的部分。此属性显然已弃用,取而代之的是 clip-path,但在撰写本文时,只有 clip 对我有用。我相信这种情况会随着时间的推移而改变,因此我们必须密切关注它,并且可以预期,Autoprefixer 会处理它。

更新!2019 年 8 月:已经过去了很多时间,clip 通常仍然受支持,但已弃用,取而代之的是(更好的)clip-pathclip 语法可以执行 clip-pathinset() 函数值的功能,因此我正在更新本文以使用它。看起来 Autoprefixer 并没有处理转换。

clip 的语法有点奇怪。对于四个值,您可能期望类似于 top/left/width/height 或 point-at-top-left/point-at-bottom-right 的内容。但实际上,它类似于 margin 和 padding:top/right/bottom/left

.glitch::before {
  clip: rect(44px, 450px, 56px, 0);
  /*
    Essentially a box from 0, 44px
    to 450px, 56px
  */

  /* clip-path: inset(); needs how far you want to push in from the edges instead */
}

以下是在这些图层上的一些示例剪辑,现在应用了完全不透明的背景(但仍然旋转并带有额外的颜色,以便您可以看到发生了什么)

动画剪辑

事实证明 clip 可以进行动画处理,因此,如果被告知,裁剪的框会随着时间的推移动画到一个新的位置。这是一个关键帧示例

@keyframes noise-anim {
  0% {
    clip-path: inset(40% 0 61% 0);
  }
  20% {
    clip-path: inset(92% 0 1% 0);
  }
  40% {
    clip-path: inset(43% 0 1% 0);
  }
  60% {
    clip-path: inset(25% 0 58% 0);
  }
  80% {
    clip-path: inset(54% 0 7% 0);
  }
  100% {
    clip-path: inset(58% 0 43% 0);
  }
}

请注意,左值和右值保持不变,只有顶部和底部发生变化。并且这些值有点随机。

您可以使用 Sass 轻松生成它,例如

@keyframes noise-anim {
  $steps: 20;
  @for $i from 0 through $steps {
    #{percentage($i*(1/$steps))} {
      $top: random(100);
      $bottom: random(101 - $top);
      clip-path: inset(#{$top}% 0 #{$bottom}% 0);
    }
  }
}

因为您需要两组随机的剪辑位置,所以您将创建这两组 @keyframes,并将它们应用于副本

.glitch::before {
  ...

  animation: glitch-anim-1 2s infinite linear alternate-reverse;
}

.glitch::after {
  ...

  animation: glitch-anim-2 2s infinite linear alternate-reverse;
}

在那里我们设置速度(关键帧的数量也影响速度)以及使其无限地来回运行。

观看它很有趣

虽然应该不言而喻,但少即是多。

Sass @mixins

我认为如果该技术更可重用会很不错。基本上,使用参数调用 @mixin 以控制效果并获得您需要的内容。

.example-one {
  font-size: 100px;
  @include textGlitch("example-one", 17, white, black, red, blue, 450, 115);
}

这是我的看法

/*
  (TEXT) PARAMS
  =================
  1. Namespace
  2. Intensity
  3. Text color
  4. Background color (flat)
  5. Highlight #1 color
  6. Highlight #2 color
  7. Width (px)
  8. Height (px)
*/

@mixin textGlitch($name, $intensity, $textColor, $background, $highlightColor1, $highlightColor2, $width, $height) {
  
  color: $textColor;
  position: relative;
  $steps: $intensity;
  
  // Ensure the @keyframes are generated at the root level
  @at-root {
    // We need two different ones
    @for $i from 1 through 2 {
      @keyframes #{$name}-anim-#{$i} {
        @for $i from 0 through $steps {
          $top: random(100);
          $bottom: random(101 - $top);
          #{percentage($i*(1/$steps))} {
            clip-path: inset(#{$top}% 0 #{$bottom}% 0);
          }
        }
      }
    }
  }
  &::before,
  &::after {
    content: attr(data-text);
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    background: $background;
  }
  &::after {
    left: 2px;
    text-shadow: -1px 0 $highlightColor1;
    animation: #{$name}-anim-1 2s infinite linear alternate-reverse;
  }
  &::before {
    left: -2px;
    text-shadow: 2px 0 $highlightColor2; 
    animation: #{$name}-anim-2 3s infinite linear alternate-reverse;
  }
}

有无数种不同的方法可以实现它,这只是其中一种。完全取决于您希望 mixin 为您做多少事情、您希望或需要的可定制性程度、您希望在 HTML 中保留哪些内容等。

我还制作了另外两个 mixin,一个用于将此效果应用于图像,另一个用于内联 SVG。它们有所不同,因为它们不使用伪元素来制作副本,着色方式不同,定位方式也不同等。这三个放在一起。

以及一个演示

查看 CodePen 上 Chris Coyier (@chriscoyier) 编写的
CSS 故障文本

CodePen 上。