使用SVG和裁剪实现文字斑点动画

原文: Animate a Blob of Text with SVG and Text Clipping
作者: Zach Saucier

大致思路是用SVG做背景,SVG text做裁切路径。使用SVG而不是用CSS裁剪图像,是因为要实现背景动画的话CSS就需要一个gif的动态图片。

首先需要创建一个由SVG图形组成的背景。这里使用椭圆形斑点的形状。需要注意的是将矢量图软件中的画板/画布大小设置成和最终效果里的viewBox相同的尺寸。(Inkscape中在文档属性下的缩放选项)

目标是用各种各样的形状覆盖画板的大部分位置,最好有一些形状互相重叠。

接着在<clipPath>中添加一些文字,把组成背景的路径聚集在一个<g>元素中,并在上面应用CSSclip-path属性,将文字作为显示的剪切区域。代码如下:

<svg viewbox="0 0 700 225">
  <clipPath id="textClip" class="filled-heading">
    <text y="70">We are</text>
    <text y="140">Creators</text>
    <text y="210">+Innovators</text>
  </clipPath>

  <g id="background" clip-path="url(#textClip)">
    <path d="m449.78..." />
  </g>
</svg>

目前为止还没有给背景添加动画,因此得到的效果只是一些纯文字的样式。

那么动效如何实现?可以使用一些简单的CSS动画:

/* 背景图形动画 */
#background path {
  animation: pulse 4s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite;

  /* 让SVG对象缩放时保持原来的位置 */
  transform-origin: 50% 50%;
  transform-box: fill-box;
}

@keyframes pulse {
  /* 缩放的同时增加一些旋转角度,效果会更有趣 */
  0%, 100% { transform: scale(0) rotate(33deg); }
  35%, 65% { transform: scale(1) rotate(0deg); }
}

注: 一般html元素中的 transform-origin 是相对元素本身,SVG元素中的是相对于SVG画布,所以这里设定 transform-box: fill-box; 让path在旋转缩放时候位置不变,参考: Transforms on SVG Elements

需要注意的是 transform-box: fill-box; 属性IE浏览器不支持,所以要兼容IE的话可以参考这里:javascript - SVG Scale without moving location - Stack Overflow

可以使用文字编辑器或矢量软件给图形绘制(指定)颜色,但是动态生成的颜色会更有意思。比如:

// 定义颜色数组
const colors = ['#f5a147','#51cad8','#112b39'];
// 选择SVG路径
var blobs = document.querySelectorAll("path");

// 随机填充颜色
blobs.forEach(blob => {
  blob.style.fill = colors[Math.floor(Math.random() * colors.length)];
});

为了在每次循环中改变文字内容,首先要把它们都添加到SVG clipPath中

<clipPath id="text" class="filled-heading">
  <text y="70">We are</text>
  <text y="140">Creators</text>
  <text y="210">+Innovators</text>
  
  <text y="70">We are</text>
  <text y="140">Movers</text>
  <text y="210">+Shakers</text>
  
  <text y="70">We are</text>
  <text y="140">Stylish</text>
  <text y="210">+Techy</text>
</clipPath>

然后可以使用CSS或者JavaScript指定文字的展示顺序。不幸的是我们不能用<g>元素来包裹<text>,因为它在clipPath中并没什么卵用。这里将它们分割为三个CSS动画,每组包含三个路径:

/* 路径 1-3 */
#textClip text:nth-of-type(n + 1):nth-of-type(-n + 3) {
  animation: showFirst 12s infinite;
}

/* 路径 4-6 */
#textClip text:nth-of-type(n + 4):nth-of-type(-n + 6) {
  animation: showSecond 12s infinite;
}

/* 路径 7-9 */
#textClip text:nth-of-type(n + 7):nth-of-type(-n + 9) {
  animation: showThird 12s infinite;
}

@keyframes showFirst {
  0%, 33% {
    opacity: 1;
  }
  33.0001%, 100% { opacity: 0; }
}

@keyframes showSecond {
  33.0001%, 66% {
    opacity: 1;
  }
  0%, 33%, 66.0001%, 100% { opacity: 0; }
}

@keyframes showThird {
  66.0001%, 99.999% {
    opacity: 1;
  }
  0%, 66%, 100% { opacity: 0; }
}

效果:

在此基础上做一些更有趣的事:

Demo 1: 使用Inkscape工具创建一些随机图形并填充颜色,色卡可以使用颜色生成工具Re: Pleasing Color Palettes,这里选择了palx

Demo 2: 复制文字来使用 例子

Demo 3: 或者让背景图形旋转:

Demo 4: 使用CSS或者JavaScript在文字变化时改变颜色:

Demo 5: 给<text>添加x="50%" text-anchor="middle"属性可以使文字水平居中(栗子),因为是多行文本,所以垂直居中可能需要更多设置。

由于使用了SVG,这个效果自身就是响应式的,缩放不变形简直棒棒哒。

最后,还有人用另一个方法实现了同样效果 传送门

里面动画更多是用JavaScript实现

Comments
Write a Comment