如何使用 SVG 为网页上的手写文本设置动画?

Posted

技术标签:

【中文标题】如何使用 SVG 为网页上的手写文本设置动画?【英文标题】:How to animate handwriting text on the web page using SVG? 【发布时间】:2016-10-13 06:58:48 【问题描述】:

我正在尝试为我创建并保存为 SVG 的文本设置动画。到目前为止,我只能为笔画设置动画,但这不是我想要实现的。如何实现如下两个示例的动画?

http://codepen.io/se7ensky/pen/waoMyxhttps://codepen.io/munkholm/pen/EaZJQE

这是我目前所拥有的:

.test 
  width: 300px
  /*   margin:0 auto; */


.l1 
  animation: dash 15s 1;
  stroke-linecap: round;
  stroke-miterlimit: 10;
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  animation-fill-mode: forwards;
  /*fill: none;*/


.l2 
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  animation: dash 20s linear forwards;
  -webkit-animation-delay: 1s;
  /* Chrome, Safari, Opera */
  animation-delay: 1s;


.l3 
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  animation: dash 25s linear forwards;
  -webkit-animation-delay: 2.5s;
  /* Chrome, Safari, Opera */
  animation-delay: 2.5s;


.l4 
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  animation: dash 25s linear forwards;
  -webkit-animation-delay: 4.5s;
  /* Chrome, Safari, Opera */
  animation-delay: 4.5s;


@keyframes dash 
  to 
    stroke-dashoffset: 0;
  
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg class="test" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 30.1 21.8" style="enable-background:new 0 0 30.1 21.8;" xml:space="preserve">
    <g>
    	<path class="text l1" d="M16.5,9.2c-0.2-0.2-0.2-1,0.1-1.5c0.1-0.1,0.2-0.3,0.3-0.4c-1.6,0-3.2-0.3-4.7-0.1C10.8,7.3,9.5,8,9.3,8.9
    		c-0.1,0.6,0.5,0.8,0.7,1c0.1,0.1,0,0.2-0.1,0.1C9.5,10,8.7,9.4,9,8.7c0,0,0-0.1,0-0.2c0.3-1.2,1.7-1.8,3.3-1.9
    		c1.8-0.1,3.9,0.4,4.8,0.4c0.2-0.2,0.4-0.4,0.5-0.4c0.3-0.1,0.6,0.1,0.3,0.4c-0.1,0.1-0.4,0.3-0.6,0.5c-0.4,0.4-0.8,1-0.5,1.5
    		C16.8,9.2,16.7,9.3,16.5,9.2z M12.1,12.8c0.1,0.1-0.1,0.3-0.1,0.3c-0.2,0.3-0.5,0.8-0.8,0.8c-0.1,0-0.5-0.1-0.5-0.1
    		c-0.1-0.8,1.5-3.5,1.9-4.2c0.2-0.3,0.1-0.4,0.1-0.5c0.1-0.4,0.9-1.4,1.5-1.4c0.2,0,0.8,0.2,0.7,0.5c0,0-0.1-0.1-0.2-0.1
    		c-1.1,0-2.9,3.6-3.4,4.7c-0.3,0.7,0.1,0.6,0.4,0.3C11.8,13,12,12.8,12.1,12.8z" fill="red" stroke="#000" stroke-miterlimit="10" stroke- />
    	<path class="text l2" d="M14.4,12.3c-0.2,0-0.3-0.2-0.1-0.2c0.4,0,1.1-0.4,1.5-0.8c0.2-0.2,0.6-0.5,0.5-0.8c0-0.3-0.4-0.2-0.6-0.1
    		c-0.7,0.3-1.7,1.3-2,2.2c-0.3,1,0.6,1,1.4,0.7c0.9-0.4,1.7-1,2.1-1.7c0-0.1,0.1-0.1,0.1,0c0.1,0,0.1,0.1,0,0.1
    		c-0.5,0.8-1.2,1.5-2.1,1.8c-1.2,0.5-2.8,0-2.1-1.5c0.4-0.8,2.2-2.4,3.1-2.1c0.5,0.2,0.4,0.8,0.2,1.1C16.1,11.8,15,12.2,14.4,12.3z" fill="none" stroke="#000" stroke-miterlimit="5" stroke-
    		/>
    	<path class="text l3" d="M17.3,13.6c-0.2,0.2-0.1,0.5,0.4,0.4c0.6-0.2,1.5-0.9,1.5-1.6c0-0.3-0.7-0.6-0.9-0.7c-0.2-0.1-0.3-0.3-0.4-0.4
    		c-0.1,0.2-0.3,0.5-0.5,0.8c-0.1,0.1-0.3,0-0.2-0.1c0.3-0.5,0.6-0.9,0.6-1.1c0.1-0.9,1.7-1.7,2.6-1.7c0.5,0,1,0.3,0.7,0.8
    		c-0.1,0.2-0.2,0.3-0.4,0.4c-0.1,0-0.2,0-0.1-0.2c0.2-0.2,0.3-0.6,0-0.6c-0.4,0-1,0.2-1.3,0.4c-0.4,0.2-0.7,0.4-1,0.9
    		c-0.3,0.3-0.2,0.6,0.1,0.8c0.8,0.5,1.8,0.8,0.9,1.8c-0.4,0.5-1.1,0.7-1.7,0.9c-0.2,0-0.7,0.1-0.9-0.1c-0.1-0.1,0-0.3,0.2-0.5
    		c0.1-0.1,0.3-0.3,0.6-0.3c0.1,0,0.1,0.1,0,0.1C17.5,13.4,17.3,13.5,17.3,13.6z" fill="none" stroke="#000" stroke-miterlimit="5" stroke-/>
    	<path class="text l4" d="M23.6,10.2c-0.2,0.1-0.8,0.1-1.4,0.2c-0.2,0.3-0.3,0.5-0.3,0.6c-0.4,0.7-0.7,1.4-0.7,1.7c-0.1,0.5,0.2,0.8,0.6,0.6
    		c0.4-0.2,1.3-1,1.8-1.7c0.1-0.1,0.2,0,0.1,0.1c-0.2,0.4-1,1.2-1.6,1.6c-0.4,0.3-1.3,0.6-1.5-0.1c-0.1-0.3,0.1-0.9,0.4-1.5
    		c-0.1,0.1-0.2,0.3-0.5,0.6c-0.1,0.1-0.2,0-0.1-0.2c0.4-0.5,0.7-1,0.9-1.2c0,0,0.1-0.2,0.3-0.5c-0.1,0-0.2,0-0.3,0
    		c-0.1,0-0.2-0.1-0.2-0.3c0.1-0.2,0.4-0.2,0.6-0.2c0,0,0,0,0,0l0.6-1.1c0.3-0.5,0.3-0.6,0.5-0.7c0.2,0,0.4,0,0.5,0.1
    		c0.1,0.1,0,0.4-0.1,0.5C23.2,9,23.1,9,23,9.1l-0.6,1l0.2,0c0.4,0,0.7-0.1,1.1-0.1C23.9,10,24.1,10.1,23.6,10.2z" fill="none" stroke="#000" stroke-miterlimit="5" stroke-/>
    </g>
    <g></g>
    <g></g>
    <g></g>
    <g></g>
    <g></g>
    <g></g>
</svg>

View on CodePen

【问题讨论】:

[我的手写动画][1]没有链接 请确认链接 任何对此问题感兴趣的人也可能对我的问题“Can I use CSS motion paths to animate drawing glyphs?”感兴趣,该问题已被标记为与该问题重复。 【参考方案1】:

Se7ensky 动画的工作原理是它使用标准的短划线动画技术,但使用代表手绘徽标外观的轮廓来剪辑动画笔触。

所以标准的破折号动画技术的工作原理如下。你走标准路线:

<svg>
  <path d="M 10,75 L 290,75" stroke="red" stroke-/>
</svg>

然后向它添加一个破折号图案并为其位置设置动画 (stroke-dashoffset)。

.pen 
  stroke-dasharray: 280 280;
  stroke-dashoffset: 280;
  animation-duration: 2s;
  animation-name: draw;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-timing-function: linear;


@keyframes draw 
  from 
    stroke-dashoffset: 280;
  

  to 
    stroke-dashoffset: 0;
  
<svg>
  <path class="pen" d="M 10,75 L 290,75" stroke="red" stroke-/>
</svg>

最后,要获得 Se7ensky 示例的精美可变笔触宽度,您可以将那条线与您的徽标轮廓进行剪裁。

让我们假设下面这条简单的路径代表您的徽标:

<svg>
  <path stroke="black" stroke- fill="lightgrey"
        d="M 40,50
           C 110,55 195,60, 265,55
           C 290,55 290,85 265,85
           C 195,85 110,85 40,100
           C 0,100 0,50 40,50 Z"/>
</svg>

我们将其转换为一个 clipPath 元素,并使用它来将我们的动画笔划修剪为我们的徽标形状:

.pen 
  stroke-dasharray: 280 280;
  stroke-dashoffset: 280;
  animation-duration: 2s;
  animation-name: draw;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-timing-function: linear;


@keyframes draw 
  from 
    stroke-dashoffset: 280;
  

  to 
    stroke-dashoffset: 0;
  
<svg>
  <clipPath id="logo">
    <path d="M 40,50
             C 110,55 195,60, 265,55
             C 290,55 290,85 265,85
             C 195,85 110,85 40,100
             C 0,100 0,50 40,50 Z"/>
  </clipPath>
  
  <path class="pen" d="M 10,75 L 290,75" stroke="red" stroke- clip-path="url(#logo)"/>
</svg>

因此,要复制他们的示例,您需要向 SVG 添加一个连续路径(或多个路径,如果需要),表示钢笔在您的徽标中书写字母时所采用的路径。

然后使用 dashoffset 技术为该路径设置动画,同时使用原始徽标对其进行剪辑。


更新

这是一个更逼真的字母形状的最终演示:

// Simple code to enable and disable the clipping path
var chk = document.getElementById("chk");
var penpath = document.getElementById("penpath");

chk.addEventListener("input", function(evt) 
  if (evt.target.checked) 
    penpath.classList.add("clipped");
   else 
    penpath.classList.remove("clipped");
  
);
.pen 
  fill: none;
  stroke: red;
  stroke-width: 18;
  stroke-linecap: round;

  stroke-dasharray: 206 206;
  stroke-dashoffset: 206;
  animation-duration: 2s;
  animation-name: draw;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-timing-function: linear;


.clipped 
  clip-path: url(#logo);


@keyframes draw 
  from 
    stroke-dashoffset: 206;
  

  to 
    stroke-dashoffset: 0;
  
<svg>
  <defs>
    <clipPath id="logo">
      <path d="m85.77 49.77c-10.59 8.017-27.38 21.95-41.58 21.95-6.396 0-12.99-2.481-12.39-9.735l0.3998-4.199c38.38-12.03 48.17-26.15 48.17-35.5 0-7.635-7.995-9.162-14.39-9.162-25.98-0.1909-54.97 25.39-54.17 50.39 0.3998 12.6 7.196 25.01 21.79 25.01 19.79 0 41.78-17.94 53.97-31.5zm-52.37-1.336c5.397-12.6 16.99-21.76 26.98-24.24 1.399-0.3818 2.399 0.7635 2.399 2.1 0.1999 3.245-11.79 16.42-29.38 22.14z"/>
    </clipPath>
  </defs>
  
  <path id="penpath" d="m39.02 51.1c5.361-1.771 10.04-4.182 15.98-7.857 6.019-3.933 9.841-7.728 12.77-10.71 1.403-1.369 12.03-15.97-7.857-13.93-9.824 1.01-19.62 8.3-26.16 14.91-6.538 6.61-10.42 14.51-11.96 22.23-2.559 12.76 1.807 26.19 21.07 23.48 13.96-1.965 32.59-14.55 43.66-25.54" class="pen clipped"/>
</svg>


<p>
<input id="chk" type="checkbox" checked="true"/> <label for="chk">Enable clipping path</label>
</p>

【讨论】:

很好的答案!这里有一些 LESS 代码,我认为可以让它变得更容易:codepen.io/hesyifei/pen/Wymgxr【参考方案2】:

该示例看起来像是 svg 路径和延迟动画的组合。

CSS-Tricks 的这篇博客文章很好地解释了这一点(请注意,svg 必须有笔画才能工作): https://css-tricks.com/svg-line-animation-works/

以下是有关 stroke-dashoffset 的指南(用于示例),可能有用: https://css-tricks.com/almanac/properties/s/stroke-dashoffset/

【讨论】:

感谢您的回答,我了解 stroke-dashoffset 的工作原理。我的问题是从 text 创建一个 svg ,它有一个笔触但没有任何填充。所以我只能为中风制作动画。我用示例更新了我的链接。希望它能让我更清楚地了解我想要达到的目标。 您需要将实际的 svg 编辑为仅笔画...我看到您使用 illustrator 生成图像,因此请尝试在 illustrator 上编辑 svg。这可能意味着编辑实际的形状,如果您需要更多帮助,可以尝试在这里询问graphicdesign.stackexchange.com 我没有时间提供解释,但this pen 是我如何使这项技术为我工作的一个例子。 ...如果我不是那么挑剔地对每个字母进行动画处理,在前一个字母有足够的时间进行部分绘制之后...(例如,为F 设置动画需要 2.1 倍的时间)比o,使用谷歌脚本字体Parisienne。)This demo说明StrokeDashArrayStrokeDashOffset的效果。 (不需要插画)

以上是关于如何使用 SVG 为网页上的手写文本设置动画?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 SVG 动画无缝流畅?

如何使用 React-Native 和 Reanimated 2 为 svg 设置动画道具变换

使用填充为 svg 设置动画

仅在将鼠标悬停在圆圈上时才沿文本路径为 SVG 文本设置动画

逐渐为 SVG 设置动画

如何使用SVG动画来制作游戏