在本文中,我想强调使用SVG图形,SVG动画(包括路径),解决它们的问题和方法以及各种陷阱的复杂性,其中有很多SVG。 我将本文定位为详细指南。

不会有插件,库等,我们只会谈论纯SVG。
我将使用的唯一工具是Adobe Illustrator。
前言
一切都从无聊的演讲开始,为了希望至少能娱乐自己,我决定学习SVG图形,即动画。 令我惊讶的是,互联网上的信息很少。 到处都有重复的信息来解释基本知识,但一般来说,动画是通过2-3个链接的力量和绝对相同的信息来实现的,这是Sarah Suydan撰写的文章SVG动画指南(SMIL)的译文。
她的文章浅谈了一切。 但是,我强烈建议您熟悉它。 *链接到翻译*接下来的几周,我花了很多时间从各个来源收集信息。 这些搜索的结果是本文。
从Illustrator正确导出SVG
本节重点介绍Adobe Illustrator的功能和问题,因此,如果您不使用Illustrator,则可以跳过此部分。
为动画制作文档是一个非常重要的阶段,忽略它会导致非常不愉快的后果。 教您如何在Illustrator中更好地绘画,我不会。 我唯一要说的是,在绘制形状时,应该遵循这些值,希望它们在小数点后只有一个数字,最好是整数。 遵循此规则不是必需的,但是它将减小文件大小,简化进一步的动画制作,并在视觉上减少信息量。 看一下
<path d="M 17.7 29 C 28.2 12.9 47 5.6 62.8 10.4 c 28.2 8.5 30 50.5 24.8 53.1 c -2.6 1.3 -10.4 -6.1 -29.2 -34.6"/> <path d="M 17.651 28.956 c 10.56 -16.04 29.351 -23.359 45.12 -18.589 c 28.151 8.516 29.957 50.5 24.841 53.063 c -2.631 1.318 -10.381 -6.148 -29.235 -34.643"/>
在示例中,曲线相同,但是在第一种情况下,小数点后一位,在后三位。 该曲线只有4个点,第二个示例比第一个示例长三分之一。 想象一下20点曲线将占用多少空间。
绘制线框后,需要将图像另存为SVG文件。 有两种方法可以执行此操作-另存为或导出为。 但是选择哪种方式呢? 如果您信任我,最好使用“另存为”。 如果您想知道原因,请部署扰流板。
那为什么呢乍一看,这没有什么区别,因为最后我们得到了带有图像的.svg文件。 但是,差异始于导出设置阶段。
我看不到详细解释所有参数的意思,Illustrator在“说明”部分中做得很好。如您所见,“保存”具有比“导出”更多的设置,对于某些情况,这是拒绝导出的充分理由,但我们将继续。
如果我们在浏览器中打开以两种方式保存的文件,我们将不会注意到两者之间的差异。 但是,此刻,我们对外观而不是填充更感兴趣,因此我们将通过文本编辑器进行相同的操作。 在这里,差异将变得更加明显。 我建议您自己查看并得出结论,我没有更改文件中的任何内容,只是直接复制了整个内容。
汇出 <svg id="_1" data-name=" 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 51 51"> <defs> <style> .cls-1 { fill: none; stroke: #4ec931; stroke-miterlimit: 10; } .cls-2 { fill: #4ec931; } .cls-3 { fill: #fff; } </style> </defs> <title>my_icon_E</title> <circle class="cls-1" cx="25.5" cy="25.5" r="20"/> <circle class="cls-1" cx="25.5" cy="25.5" r="25"/> <g id="_2" data-name=" 2"> <circle class="cls-2" cx="25.5" cy="25.5" r="15"/> <polygon class="cls-3" points="25.5 34.8 34 20.3 17 20.3 25.5 34.8"/> </g> </svg>
保存到 <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" id="_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve"> <style type="text/css"> .st0{fill:none;stroke:#4EC931;stroke-miterlimit:10;} .st1{fill:#4EC931;} .st2{fill:#FFFFFF;} </style> <circle class="st0" cx="50" cy="50" r="20"/> <circle class="st0" cx="50" cy="50" r="25"/> <g id="_2"> <circle class="st1" cx="50" cy="50" r="15"/> <polygon class="st2" points="50,59.3 58.5,44.8 41.5,44.8 "/> </g> </svg>
除了在命名CSS类和设计的总体上有所不同(有些人可能认为它们有品位)之外,还有其他问题。 “导出”时,整个图像将缩小2倍。 您可以通过形状的大小和
viewBox属性来判断。 由于这是矢量图形,因此情况并没有恶化,但仍然令人不快。 “保存”保留了我在Illustrator中指定的尺寸。
但是,与“出口”猪所能放的猪相比,这些都是花。 具体来说,这些示例没有此问题,可能是因为图像非常简单。 但是,我在导出其他作品时遇到了它。 这是她的截图

文件大小足够大,所以我只给出问题部分
<g id="-21" data-name=""> <path class="cls-9" d="M477.94,456.75a1.83,1.83,0,0,1-.9,1.36l-4.91,3.1a7.29,7.29,0,0,1-7.5,0l-16.29-9.72a1.85,1.85,0,0,1-.92-1.56v-3.68a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l4.53-2.86.38-.23a1.87,1.87,0,0,0,.9-1.36Z" transform="translate(-5.5 -5.5)"/> <path class="cls-10" d="M477,451.19l-16.38-9.5a7.28,7.28,0,0,0-7.32,0l-5,2.9a1.88,1.88,0,0,0-.94,1.51v.17a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l4.53-2.86.38-.23a1.87,1.87,0,0,0,.9-1.36v-.51A1.88,1.88,0,0,0,477,451.19Z" transform="translate(-5.5 -5.5)"/> </g> <g id="-22" data-name=""> <path class="cls-9" d="M525.37,557.86a1.85,1.85,0,0,1-.9,1.36l-33.22,19.64a7.29,7.29,0,0,1-7.5,0l-16.29-9.72a1.85,1.85,0,0,1-.92-1.56v-3.68a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l32.84-19.41.38-.23a1.83,1.83,0,0,0,.9-1.36Z" transform="translate(-5.5 -5.5)"/> <path class="cls-10" d="M524.45,552.3l-16.38-9.51a7.31,7.31,0,0,0-7.32,0l-33.27,19.44a1.89,1.89,0,0,0-.94,1.51v.17a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l32.84-19.41.38-.23a1.83,1.83,0,0,0,.9-1.36v-.5A1.86,1.86,0,0,0,524.45,552.3Z" transform="translate(-5.5 -5.5)"/> </g>
注意到有什么不寻常的地方吗? 如果您对
转换属性存有疑问,那您是对的。 是他破坏了整个树莓。 当“导出”图像时,Illustrator会将其分配给所有
<path>元素。 但是,“保护”并没有观察到这样的问题。
如果您仍然不理解我的愤慨,那么我将解释:如果您想动画化这样一个元素的运动,那么它将转移到一边。 在这种情况下,两个轴均为5.5。 这是因为运动动画会更改
transform属性,从而重置所有过去的值。 当然,可以绕开它,但是避免该问题不是比稍后更正其后果更好的方法...
目前,我仅注意到此问题,但这并不意味着它是唯一的问题。 如果您明智地评估这种情况,那么事实证明,“另存为”会赢得一切。 因此,我建议您使用它。
将SVG文档导入HTML的方法
在直接开始制作动画之前,我想谈谈如何在页面上嵌入SVG。 每种方法都有其自己的“特征”,这些特征直接影响动画。 而且,如果您不谈论它们,那么本文将是不完整的。
假设您已经拥有带有交互式动画的现成的SVG,并且可以将其嵌入网站中。 怎么做?
第一种选择是记住SVG也是图像,可以使用标准HTML工具导入。 您可以创建带有文档链接的
<img>标签 <img src="Hello_SVG.svg" />
或将SVG设置为背景图像
#box { background-image: url("Hello_again.svg"); }
这种方法的主要缺点是图像的隔离。 SVG作为博物馆的展览品-您可以观看,无需触摸。 里面的动画将起作用,但是不能谈论任何交互性。 例如,如果动画是由用户单击触发的,或者需要动态更改SVG文档的内容,则此方法不适合您。
第二种方法是使用
<object>或
<embed>标签从SVG创建对象。 也可以使用
<iframe>创建框架,但是不建议使用此方法,因为 所有浏览器都需要
拐杖 ,以便该选项正确显示
<object data="My_SVG.svg" type="image/svg+xml"></object> <embed src="My_SVG.svg" type="image/svg+xml" /> <iframe src="My_SVG.svg"></iframe>
这里的情况更好。 动画有机会进行交互,但前提是必须在SVG文档中声明动画,并且这些内容可用于外部JavaScript。 如果突然没有加载图像,
<object>和
<iframe>仍然可以显示存根。
第三种选择是将SVG文档的内容直接直接粘贴到HTML中。 是的,可以。 SVG支持出现在
HTML5标准中 。 由于SVG本质上是页面本身的一部分,因此无处不在对其进行访问。 元素的动画和样式可以在SVG内部和外部文件中声明。 不利的一面是,此类图片不会与页面分开缓存
<body> ... <svg> </svg> </body>
SVG动画
设置SVG元素的动画有两种主要方法:
- CSS动画
- SVG中内置的SMIL动画(实际上,它是基于SMIL并扩展其功能的SVG动画)
我个人将它们分为“外部”和“内部”的动画。 这种划分是有条件的,但是它们仍然在功能上有所不同。 如果我们通常谈论差异:CSS-对浏览器有更好的支持; SMIL-具有强大的功能。 很难说哪种更好,因为 他们很像。 选择取决于任务,所以我只想说说使用SMIL而不是CSS的主要原因
SMIL-需要时:
- CSS无法执行的操作(设置不受支持的属性的动画等)
- 对动画有更精确的控制。
- 进行路径变形( 路径标记处的属性d的动画)
- 同步动画
- 制作互动动画
如果我写过SMIL应该用于交互式动画,这并不意味着CSS不能做到这一点。 Simply SMIL是一种功能更强大的复杂工具。 这就是为什么仅在必要时才使用它的原因。 如果动画很简单并且可以省去CSS,则应该这样做。
CSS动画
这里没有新内容。 我们可以像处理HTML一样对SVG元素进行动画处理。 所有动画都是使用
@keyframes创建的。 由于CSS动画是另一个主题,因此我不会在这一点上进行详细介绍,因此网络上充斥着有关该主题的文档和指南。 此处描述的所有内容都适用于SVG,但我仅举几个例子。
SVG文档具有内部样式表,因此我们将在其中编写动画
<svg> <style> </style> </svg>
动画SVG属性就像CSS属性一样简单
@keyframes reduce_radius { from { r: 10; } to { r: 3; } } @keyframes change_fill { 0% { fill: #49549E; } 75% { fill: #1bceb1; } 100% { fill: #1bce4f; } }
您可以将值指定为百分比,并从头到尾构造然后剩下的只是将创建的动画应用于所需的元素
.circle { animation: change_fill 1s, popup 2s; }
我上面描述的只是静态动画,没有交互的气味。 但是,如果您真的想要呢? 好了,仍然可以在CSS中以交互方式完成某些工作。 例如,如果您将
过渡与
悬停伪
类结合使用
.circle { fill: #49549E; transition: .3s; } .circle:hover { fill: #1bceb1; }
将鼠标悬停在某个项目上时,它将颜色从蓝色更改为蓝色300ms属性动画和一小部分交互性-CSS动画的功能就在这里结束。 但是此功能就足够了,因为大多数任务都归结为动画某些属性。 几乎所有SVG属性都可以设置动画。 当我写“几乎任何”时,我的意思是,如果您选择一个随机属性,但事实证明它是非不变的,那么您非常幸运。
SMIL动画
值得一提的是,SMIL动画与世界一样古老,并且正在逐渐消失,浏览器支持还不错,但仍不及CSS动画,但是有一个原因使SMIL仍然具有吸引力-可以,因为CSS不能。
我将谈论更多关于SMIL的问题,因为存在很多他们很少写的陷阱。 而且这个主题不如CSS流行。 动画的主要标签是
<animate> ,
<set> ,
<animateTransform>和
<animateMotion> 。
<动画>
让我们从重型火炮开始。
<animate> -用于设置任何属性的动画,是主要工具。 其余的标签是高度专业的,但首先要注意的是。
如何将动画应用于元素?有两种方法可以指定将动画应用到的元素。
- 将标签放在元素内。 此方法使您可以将动画封装在对象内部,从而更易于阅读代码
<circle ...> <animate .../> </circle>
在这种情况下,动画将应用于circle元素。 - 将链接传递到项目。 如果您希望将所有动画收集在一处,则很有用
<svg xmlns:xlink="http://www.w3.org/1999/xlink"> <circle id="blue" .../> ... <animate xlink:href="#blue" .../> </svg>
这里使用xlink:href属性,在其中我们指定动画应应用于的元素的ID 。 为了使此方法起作用,必须定义xlink命名空间。 这是在<svg>标记中完成的。
在SVG 2中,不建议使用
xlink:href属性,该规范建议改为使用
href ,因为
href不需要
xlink命名空间。
<circle id="blue" .../> ... <animate href="#blue" .../>
但是在这里,并不是一切都那么顺利
-Safari不支持
href 。 结果是陷入僵局,一个属性已过时,另一部分属性不被支持。 因此,使用哪种方法,每个人都可以自己决定。
对于那些已经注意到与CSS选择器相似的人:令人失望的是,我将无法按类访问元素
<circle class="blue_circle" .../> <animate href=".blue_circle" .../>
这行不通!如何为动画指定属性?为此有
attributeName 。 该值是我们要设置动画的属性的名称。
<circle r="25" ...> <animate attributeName="r" ... /> </circle>
通过在attributeName中指定r ,我们报告我们将对圆的半径进行动画处理什么是attributeType?为什么不需要它?因为他没用从理论上讲,CSS和XML中的属性名称匹配时可能会出现片刻,这可能会导致问题。 为了解决此冲突,必须显式指定一个名称空间。 有两种方法:指定前缀或使用
attributeType 。 让我们从前缀开始。
他们到处写着如下内容:
您可以为属性指定XMLNS前缀,以明确指定其名称空间
顺便提及了该方法,没有示例。 所以我不会改变传统。 (我建议您在这里停止,不要把前缀当作噩梦,而转到
attributeType ,我警告过您)
我是受虐狂这个破坏者的内容本质上是娱乐性和探索性的。 没有有用的信息,除了前缀不起作用的事实之外,您不会在这里找到首先,您需要找到一个更准确的定义,并且,如您所知,在规范和标准中找到最准确的定义。
放弃生活的简短指南- 我们将于2019年3月14日开放SVG动画的规范
- 在attributeName部分,我们看到它继承了 (恐怖)2001年的SMIL动画标准 。
- 阅读attributeName的定义
- 赢利!
该定义的翻译如下:
“定义目标属性的名称。 XMLNS前缀可用于指定属性的XML名称空间。 前缀将在animation元素的范围内解释。”
嗯,这并没有变得容易。 在阅读了这样的定义后不了解XML的人会想到什么? 对啊 和我一样
我从字面上看,认为它应该像这样
<animate attributeName="xmlns:* *"/>
在撰写本文之前,我曾想过并安全地忘记了这种方法。 当我决定在实践中进行测试时,问题就开始了。 如果我说这行不通,我想我不会感到惊讶。 经过几个小时的搜索失败后,我用google搜索了“ xmlns前缀”,令我惊讶的是,我发现xmlns本身并不是前缀,而是
(集中说明,现在很难) 带有前缀 的 名称空间设计 。
它看起来如下:
<** xmlns:**="* url *" ...>
然后我意识到……一开始我什么都不懂……现在,原则上也是如此几个小时后,我终于
在XML的命名空间中找到了我想要的东西。 这是原始示例:
<x xmlns:n1="http://www.w3.org" xmlns="http://www.w3.org" > <good a="1" n1:a="2" /> </x>
但是你知道最有趣的是什么吗? 它仍然不起作用。 虽然一切都按书完成
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:n1="http://www.w3.org/2000/svg"> <circle id="www" n1:r="10" .../> <animate href="#www" attributeName="n1:r" .../> </svg>
没有错误,也不应该错误,因为一切都是按照规则完成的,但是问题是我们得到了一个没有半径的圆。 如果您根本不编写
r属性,将会得到相同的结果。
结语 :SVG忽略带前缀的属性。 因此,即使SMIL确实使用前缀对属性进行动画处理,您也不会看到此动画的结果。
为了辩护,我要说的是,我只处理SVG,即涉及其动画,因此XML专家会将火把和干草叉放在一边。 如果您知道如何使此方法起作用,欢迎发表评论 为了明确指示动画属性属于什么,使用attributeType。 它需要3个值:
CSS ,
XML ,
auto 。 除非明确指定
attributeType ,否则将使用
auto 。 在这种情况下,将首先检查CSS属性,如果没有匹配项,则将检查目标元素的属性。 在示例中,我们指示我们将精确地对CSS属性进行动画处理
<animate attributeType="CSS" attributeName="opacity" .../>
好吧,
attributeType允许您轻松无without地指示动画属性属于什么,从而解决甚至不存在的“问题”。
没想到吧? 正如我在本章开始所说的那样,SMIL快要死了,这是因为动画已转移到CSS的导轨上。 大多数重复的属性彼此绝对相同,即 CSS或SMIL属性属于哪个都没关系-结果将相同。 结合默认的
自动值,不再需要显式定义
attributeType 。
有趣的一刻: SVG不支持attributeType 。 他从哪里来? 他来自SVG动画所基于的SMIL Animation。 SVG 1.1 Second Edition之后, attributeType也被删除。 这里的所有证明如何确定动画值?为动画指定属性是不够的;您必须定义其值。 这里来自
价值 ,
来自 价值 。
让我们
从永远在一起的一对夫妇开始:
from和
to 。 它们存在的意义很明显,
从表示开始
到结束
<circle r="25" ...> <animate attributeName="r" from="10" to="45" .../> </circle>
动画的结果是圆的半径从10平滑变为45即使我说过它们始终在一起,也可以在不明确声明
from的情况下使用
to 。 在这种情况下,
from将采用目标元素中定义的值。 对于上面的示例,动画将从25开始。
如果需要指定一组多个值,则使用值。 值以分号列出。
<circle r="25" ...> <animate attributeName="r" values="15;50;25" .../> </circle>
半径值减小到15,然后增大到50,然后返回到其原始位置。排在最后。 他不在乎“哪里”和“哪里”,他感兴趣的只是“多少”。 换句话说,它使用绝对值而不是绝对值
<circle r="25" ...> <animate attributeName="r" by="15" .../> </circle>
作为动画的结果,半径将增加15,即得到25 + 15 = 40在手册的范围内都有一个传说,
“可以用于指示动画前进的数量 。
” 我这样理解:如果
从= 20 到= 50 并由= 10给出,那么必须通过“跳”入10来克服此路径,即 20、30、40、50。但是无论我如何尝试,无论有无动画都没有改变。 另外,我在规范中没有找到确认。 看来这只是一个错误。
值具有最高优先级,然后
从 -
到最后
是 。 最低优先级
通过来解释为什么“传说”原则上不能起作用。 但是,
通过与
from结合使用,在这种情况下,
from会简单地覆盖元素的当前位置
<circle cy="50" ...> <animate attributeName="cy" from="70" by="30" .../> </circle>
在这里,动画从50开始而不是50开始,到100结束有关相对动画的更多信息您可以使其他属性的作用与
by相同。 这是通过使用
additive属性完成的,该属性具有两个位置
-replace和
sum 。
第一个是默认设置,因此我们对第二个感兴趣。使用总和值,所有属性将被添加到目标元素的当前值,即 当使用值form = 5和to = 15设置半径20 的动画时,动画将为20 + 5到20 + 15 <circle r="20" ...> <animate attributeName="r" from="5" to="15" additive="sum" .../> </circle>
在执行动画时,将急剧跳到位置25,这不好(当然,除非这样做是有意的)。可以通过form = 0来避免这种情况,但是失去了使用sum的含义,因为无需添加使用by就可以获得相同的效果。 <animate attributeName="r" from="0" to="15" additive="sum" .../> <animate attributeName="r" by="15" .../>
对我来说,第二种方法更容易理解和方便,在哪里指定动画的持续时间?剩下的最后一个必需属性是制作动画-这是 dur。该属性值确定动画的持续时间,可以以秒和毫秒为单位进行指定 <animate dur="0.5s" .../> <animate dur="500ms" .../> <animate dur="00:00:00.5" .../>
从最后一行,您可以猜测还有其他内容……您还可以用分钟甚至数小时来指示值 <animate dur="1.2min" .../> <animate dur="0.02h" .../>
Fuck知道,您为什么要设法在几个小时内指示出这些值,但我却没有去处理别人的事务,这意味着为什么...对于其他属性,临时值是以相同的形式设置的,我该怎么做以防止动画返回到开头? 填充属性(不要将此属性与其名称混淆)负责动画结束后元素的行为。有两种选择: - remove(默认值)-动画结束时,所有变换都会重置,并且元素将采用与动画之前一样的状态
- 冻结 -元素冻结在动画的最终位置
是否可以循环播放动画?答案是肯定的。为此,repeatCount属性指定一个不确定的值。该属性确定动画的重复次数,默认为1,但是您可以指定任意数量 <animate repeatCount="indefinite" .../> <animate repeatCount="3" .../>
第一个动画 会无休止地重复,第二个动画会工作3次,现在无休止的动画让我烦恼,我可以在一段时间后关闭它们吗?对于这样的烦人,人们重复了Dur。从动画开始一定时间后,此属性将停止动画!简而言之, repeatDur限制了动画的持续时间。与 repeatCount的主要区别在于动画可以在中间停止 <animate dur="2s" repeatCount="indefinite" repeatDur="3s" .../>
动画将在第二次迭代的中间中断,如果我不希望动画立即开始怎么办?然后,我的朋友为您提供了 begin属性。他负责动画的开始时间。此属性非常有用,因为它还用于同步多个动画,但稍后会进行更多介绍。如果您需要指定启动的通常延迟时间,那么我们会写出打开文档后动画应在多长时间内开始播放 <animate begin="1.5s" .../>
播放会在1.5秒后开始,您也可以指定一个负值。然后,动画将不会从头开始,而是在指定时间段后的位置开始 <animate begin="-2s" dur="4s" .../>
动画将从文档的开头开始,但将从中间 开始播放,我们使动画具有交互性,作为开始值,您可以指定动画开始时的事件,但不带“ on”前缀。例如,如果您要制作点击动画,而不是“ onclick”,我们会写“ click” <circle ...> <animate begin="click" .../> </circle>
在上面的示例中,当您单击应用了动画的元素时,动画开始。如果要从另一个元素开始对事件进行动画处理,则需要指定其id <circle id="button" .../> ... <animate begin="button.click" .../>
您还可以为动画的开始指定几个条件。为此,将它们列出,并用分号分隔。 <animate begin="click; 0s" .../>
当加载文档并单击时,动画将开始,虽然不支持所有事件,但是大多数与鼠标有关的事件都可以工作。我就不一一列举了所有可用的事件,你可以找到的地方 在这里。同样,没有人取消科学扑克的方法。动画将重新启动而没有结束,如何解决它?我将举一个简单的例子。单击此处开始动画。如果用户仍然不按,则在3秒钟内提供自动启动 <animate begin="click; 3s" dur="7s" .../>
但是有一个问题:如果用户在自动计时器之前按下,则3秒钟过后,动画将重新开始,并且永远不会结束。当whenNotActive值中的restart属性可以解决。总共他有三个- 始终是默认设置-允许您随时重新启动动画
- whenNotActive-如果尚未播放动画,则可以开始
- 从不 -禁止重新启动动画
<animate begin="click; 3s" dur="7s" restart="whenNotActive" .../>
问题已得到解决,尽管在大多数情况下,您可以通过简单地胜任地构建依赖关系来消除此属性,但动画的同步除标准事件外,还包括单击事件的类型,单击的类型,动画的开始,结束和重复。为了领带事件,你必须指定 ID通过的点动画和的开始,结束,重复的分别 <animate id="pop" begin="click" .../> <animate begin="pop.begin" .../> <animate begin="pop.end" .../>
如果对于前两个,一切都清楚了,那么对重复来说,一切都不那么明显。重复次数写在括号中,之后您需要启动动画(此数字不能是最后一次重复) <animate id="flip" repeatCount="5" .../> <animate begin="flip.repeat(2)" .../>
动画将在两次重复后开始,而不是每两次重复。您还可以指定相对于事件的延迟。例如,如果我想在另一个开始后 2秒钟播放动画 <animate id="another" .../> <animate begin="another.begin + 2s" .../>
或在另一个结束前一秒钟开始播放动画 <animate begin="another.end - 1s" .../>
还有什么可以开始的...我想称呼此部分,但更正确的称呼为“他应该能够但不能?”。根据我最喜欢的规范,begin应该有另外两个值。第一个是accessKey,它通过按Unicode格式指定的键来启动动画。第二个是wallclock,它实时确定动画的开始。在这里,您不仅可以指定时钟,还可以指定完整的月份和年份。不幸的是,他们都不想工作。尽管损失不是很大,但是由于对它们的需求仍然不确定 <animate begin="accessKey(\u0077)" .../> <animate begin="wallclock(2019-04-09T19:56:00.0Z);" .../>
我不知道问题出在哪里,也许我的浏览器不支持它们,或者其他...我可以中断动画吗?这可以通过 end属性来完成。在使用中,它与 begin相同,也可以指定时间,事件等。如您所见,这不是中断动画的第一种(也是最后一种)方法,因为这里有 repeatDur,您还可以在其中固定动画的持续时间。尽管您还可以直接在结束时指定时间,但它的独特功能是事件绑定和指定值列表的功能。假设我们有一个具有休息和活动状态的元素。单击时激活第二个。我们希望从活动开始就中断其余动画。您可以实现类似的想法 <animate id="idle" end="action.begin" begin="0s" repeatCount="indefinite" .../> <animate id="action" begin="click" .../>
默认情况下会启动其余动画。当您单击一个元素时,活动动画将开始并中断其余动画。将属性end和begin组合在一起正如您已经知道的那样, begin和 end都可以采用值列表,但是如果您同时在两个属性中都指定一个列表,则动画的表现还不清楚。结果将以某种方式在一定的持续时间和间隔之间进行重复,这还不清楚吗?我现在将解释所有内容。首先要知道的是列表中值的数量必须匹配。每对开始 -结束值定义一个“重复”。从一个“重复”的结束到下一个“重复”的开始之间的时间确定了延迟。我称它们为“重复”是有原因的,动画不会暂停并继续,但是会中断并从头开始。事实证明,我们可以分别调整每次重复的持续时间,并在每次重复之后设置不同的延迟 <animate dur="3s" begin="1s; 5s; 9s" end = "2s; 8s; 11s" .../>
在此示例中,动画具有3个“重复”。第一次将在加载文档后一秒开始,并且仅持续三分之二秒。然后是3秒的延迟,然后是3秒的完整动画。再次,延迟,但在1秒内。动画两秒钟后,最后一次重复将被中断,您是否仍可以以某种方式中断动画?存钱罐Keeneeee有几个无用的属性,还有另外两个属性 -min和 max。顾名思义, min定义最小值, max定义最大持续时间。首先,动画持续时间是使用值 dur, repeatCount, repeatDur,结束。然后,将获得的持续时间调整为min和max指定的帧。一切在纸上都是美丽的,让我们看看它如何在实践中发挥作用。使用max,一切都很简单,这是定义上限的另一个属性。如果计算的持续时间小于max,则将其忽略;如果计算的持续时间更长,则动画的持续时间将等于max <animate dur="10s" repeatDur="7s" end="5s" max="4s" .../>
它会被中断4秒钟,但是 min不幸的是。如果计算的动画持续时间长于 min,则将其忽略,这是合乎逻辑的。但是,如果计算出的持续时间小于 min,则它...有时会被忽略,有时不会被忽略。为什么为什么?这一刻很容易让人困惑,因此请仔细阅读。当计算的持续时间小于 min时,我们有两个选择:- 因为动画本身已经结束,即 dur * repeatCount < 分钟
<animate dur="2s" repeatCount="2" min="5s" .../>
在此选项中,min属性将被忽略,动画将在第四秒停止 - repeatDur end .
由于丰富的属性会打断动画,因此存在很多混乱。结果,max和min没有太大意义,因为写得好的动画消除了对它们的需要。如何管理关键帧以及在何处指示时间函数?为此,您需要了解属性keyTimes,keySplines和calcMode。在值中指定了列表之后,我们声明关键帧,但是它们分布均匀。多亏了keyTimes属性我们可以加快或减缓从一种状态到另一种状态的过渡。在其中,也以列表的形式指示每个帧的值。这些值相对于整个动画的持续时间以百分比形式表示关键帧在时间轴上的位置(0-0%; 0.5-50%; 1-100%)。有几个规则:每个值代表一个从0到1的浮点数,列表中的值数必须匹配,第一个值必须为0,最后一个为1,每个下一个值必须大于上一个。我认为您了解使用没有值的keyTimes没有意义。现在是一个例子 <animate values="15; 10; 45; 55; 50" keyTimes="0; 0.1; 0.6; 0.9; 1" .../>
默认情况下,所有转换都是线性发生的,要更改此值,您需要在calcMode中指定其他模式。而且没有太多选择:- 线性 -标准值,无需解释
- 节奏 -计算时间间隔以使关键帧之间的速度恒定
- 离散 -动画在关键帧之间切换,无需插值
- 样条曲线 -我们可以说这是一个手动控制模式(稍后介绍)
不幸的是,这些都是内置函数,在这里您不会像在CSS中那样轻松地\ \。因此,这些需求必须满足我称之为“手动”的制度。节奏最难理解,所以我将更详细地解释它。首先,请看动画如何在标准模式下工作。动画持续2秒,我们有3个关键帧-初始,中间,最终 <animate dur="2s" values="100; 200; 150" .../>
如果观看动画,很明显关键帧之间的移动是有规律的。第一和第二之间的距离是100,第二和第三之间的距离是50,即 第一种方式的一半。通过简单的计算,很明显该元素通过第二段的速度是第一段的两倍,现在添加calcMode =“ paced”并查看发生了什么变化。 <animate dur="2s" values="100; 200; 150" calcMode="paced" .../>
元素的速度已经改变。现在,它被设计为以相同的速度覆盖整个距离,换句话说,该元素将均匀地移动两个段。现在让我们看一下样条线模式和keySplines属性。他们有一些相似之处...嗯...如果样条线定义了手动模式,则keySplines属性将定义此模式的值。显然,一个不能没有另一个。keySplines中的值由一个列表设置,该列表指示三次贝塞尔曲线的两个点的坐标。有关贝塞尔三次函数的更多信息, . 4 0 1 : cubic-bezier(x1, y1, x2, y2). , .

cubic-bezier .
, .
keySplines中的值数量应比values少1 。这是由于我们指示的值不是关键帧,而是关键帧之间的间隔。 <animate values="100; 200; 150" keySplines=".25 .1 .25 1; 0 0 .58 1" calcMode="spline" .../>
Bezier函数的点的坐标由空格或逗号分隔,列表值由分号分隔。第一个也是最不愉快的减法是您无法为所有关键帧设置通用时间函数,因此必须为每个帧重复该函数。第二个-如果要为属性 from - to或 by设置时间函数,则需要拐杖:必须将 keyTimes的值设置为 “ 0; 1” <animate from="10" to="50" keyTimes="0; 1" keySplines=".25 .1 .25 1;" calcMode="spline" .../>
如果,而不是从 - 到使用值从两个值,那么这个问题将不会是如何实现动画的储蓄?首先,有一点理论-累积动画的下一次重复将在上一个结束的地方继续。这会很酷,但不是很好。累积动画仅在重复中有效的事实令人失望。现在介绍如何使动画具有累积性:您需要将 accumulate属性(默认为 none)设置为 sum <animate by="100" repeatCount="3" accumulate="sum".../>
应该记住的是,如果使用值或从 - 到,则除第一个重复外,所有重复都将表现为additive =“ sum”。而积聚如果仅指定一个忽略到。我们理解了轮廓的变形现在,我已经解释了基础知识,是时候继续研究真正酷和复杂的东西了。我确信有人只是出于本节的目的而打开了本文。路径变形是path标记的d属性的动画,它使您可以创建平滑改变形状的效果。当前,使用内置工具只能使用SMIL完成此操作。在values表示元素通过的d属性的值列表。它也可以用来从 - 到。通常,轮廓变形如下所示 <animate attributeName="d" values=" 1; 2; ..." .../>
现在让我们继续这个过程的复杂性:对于那些在坦克中的人,d属性包含一组点,这些点随后依次连接以形成图形。仔细观察即可发现,值列表与CNC机器(或计算机科学课程中的“机器人”)指令集相似。有很多团队,一些团队负责“移动光标”,另一些团队负责“绘图”,一些团队负责曲线的数量,等等。 (所有团队都在这里)。为了使变形生效,命令的数量必须匹配,并且它们必须是同一类型。如果忽略此条件,则不会进行插值-动画将从一个状态跳到另一状态,就像calcMode =“离散”。乍一看,这没什么复杂的,因此,如果要对没有曲线的形状进行动画处理,则是如此。如果没有,那么困难就开始了。创建复杂的图形时,每个人都使用矢量编辑器,他们有尽可能多地优化“代码”的习惯。这通常是一个加号,但对于我们而言并非如此。在输出中,我们可能有一个长度不一的列表,但团队类型不同,这违反了其中一项规则。我使用了Adobe Illustrator,但没有找到可以解决问题的选项。有时,按照神明神灵的意愿,这个问题不存在。但严重的是,出现问题的可能性与图形和变形的复杂程度成正比。目前,解决该问题的唯一方法是在Shape Shifter Web应用程序中转换“弯曲的代码” 。这是我使用的选项。除了修复损坏的代码外,Shape Shifter还允许您查看结果,可以选择添加其他类型的动画并以方便的格式导出结果。接下来是循序渐进的教程,我将告诉您如何制作如此精美的动画
教我!: SVG Adobe Illustrator, , Shape Shifter . CSS, SMIL .
. Illustrator. , . 200x200 .
, , . , , «». ,
. . « »
, . , , ,
. , , . , . SVG , . …
. , . SVG . ( Illustrator )
, , Illustrator
<path> ,
<circle> . , . , , . - (
SVGO ), . .
d , ) <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve"> <style type="text/css"> .st0{fill:#D38911;} .st1{fill:#87872B;} .st2{fill:#CEB629;} .st3{fill:none;stroke:#DD913E;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:12,200;} </style> <g id="Pulse"> <g> <path class="st0" d="M100,87c44.1,0,80,35.9,80,80s-35.9,80-80,80s-80-35.9-80-80S55.9,87,100,87 M100,82c-46.9,0-85,38.1-85,85 s38.1,85,85,85s85-38.1,85-85S146.9,82,100,82L100,82z"/> </g> </g> <g id="_x3F__1_"> <path id="side" class="st1" d=" "/> <path id="front" class="st2" d=" "/> </g> <g id="Particles"> <line class="st3" x1="80" y1="162.9" x2="42" y2="59.1"/> <line class="st3" x1="90.1" y1="148.8" x2="59.8" y2="28.8"/> <line class="st3" x1="107.9" y1="155.6" x2="124.9" y2="15.9"/> <line class="st3" x1="94.4" y1="160.4" x2="154.3" y2="7.2"/> <line class="st3" x1="119.3" y1="157" x2="159.2" y2="75.5"/> <line class="st3" x1="98" y1="169" x2="87.7" y2="10.7"/> <line class="st3" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> </g> </svg>
<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"> <style type="text/css"> #Pulse{fill: none; stroke: #D38911; stroke-width: 5;} #side{fill:#87872B;} #front{fill:#CEB629;} .particles{fill:none;stroke:#DD913E;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:12,200;} </style> <circle id="Pulse" cx="100" cy="167" r="85"/> <g id="Sign"> <path id="side" d=" "/> <path id="front" d=" "/> </g> <g id="Particles"> <line class="particles" x1="80" y1="162.9" x2="42" y2="59.1"/> <line class="particles" x1="90.1" y1="148.8" x2="59.8" y2="28.8"/> <line class="particles" x1="107.9" y1="155.6" x2="124.9" y2="15.9"/> <line class="particles" x1="94.4" y1="160.4" x2="154.3" y2="7.2"/> <line class="particles" x1="119.3" y1="157" x2="159.2" y2="75.5"/> <line class="particles" x1="98" y1="169" x2="87.7" y2="10.7"/> <line class="particles" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> </g> </svg>
, . , ,CSS , . . , . . CSS . :
#Pulse{fill: none; stroke: #D38911; stroke-width: 5; transform: rotateX(80deg);} ._transformer{transform-box: fill-box; transform-origin: center;}
,
_transformer , , . «»
<animateTransform> .
- :
, Illustrator? …– , . , . ,
<path> , .
, ! – , . , – .
circle , .
animate , 3
<circle id="Pulse" class="_transformer" cx="100" cy="167" r="0"> <animate id="doPulse" attributeName="r" values="0;85;" dur=".8s" begin="Sign.click" calcMode="spline" keySplines="0,0,.58,1"/> <animate attributeName="stroke-width" values="5;12;" dur=".8s" begin="doPulse.begin"/> <animate attributeName="opacity" values="0.5;1;1;0" keyTimes="0;0.2;0.5;1" dur=".8s" begin="doPulse.begin"/> </circle>
, CSS, . : , , . - :
. - , . ,
<linearGradient id="light-gradient"> <stop offset="0%" stop-color="#ffffff00"/> <stop offset="10%" stop-color="#FFF"/> <stop offset="90%" stop-color="#FFF"/> <stop offset="100%" stop-color="#ffffff00"/> </linearGradient> <mask id="light-mask"> <rect y="0" x="90" class="_transformer" width="20" height="220" fill="url(#light-gradient)" /> </mask>
, . , , . ,
<use> ,
<path> <defs> <defs> <path id="question" d=" "/> </defs> ... <use id="front" href="#question"/> <use id="light" href="#question" mask="url(#light-mask)"/>
, , . . ,
#light-mask rect{ animation: highlight 4s infinite; } @keyframes highlight { 0% { transform: translate(-100px,0) rotate(-50deg); } 30% { transform: translate(100px,0) rotate(-50deg); } 100% { transform: translate(100px,0) rotate(-50deg); } }
. . CSS , SMIL.
, . — , . ,
<g id="Sign" class="_transformer"> <path id="side" d=" "/> <use id="front" href="#question"/> <use id="light" href="#question" mask="url(#light-mask)"/> <animateTransform id="idle" attributeName="transform" type="translate" values="0,0;0,-5;0,0" dur="6s" begin="0s; jump.end" end="click" repeatCount="indefinite" /> <animateTransform id="jump" attributeName="transform" type="translate" calMode="spline" values="0,0;0,10;0,-35;0,5;0,0" keyTimes="0;0.1;0.35;0.6;1" keySpline="0,0,.58,1;0,0,.58,1;.42,0,1,1;0,0,.58,1" dur="1s" begin="idle.end" /> </g>
,, , . ,
additive="sum" <animateTransform attributeName="transform" type="scale" additive="sum" values="1,1;1.1,0.8;0.9,1.2;1.1,0.8;1,1" keyTimes="0;0.1;0.35;0.7;1" dur="1s" begin="idle.end" />
, , . 结果:
.
? - , , .
stroke-dashoffset , . ,
- . ,
<g id="Particles"> ... </g> <g id="Sign" class="_transformer"> ... </g>
, ,
.particles{ opacity:.7; stroke-width:0; ... }
, . ,
@keyframes sparks { 0% { stroke-dasharray: 20,200; stroke-width: 5px; } 100% { stroke-dasharray: 4,200; stroke-width: 0px; stroke-dashoffset: -180; } }
, . , , «». : CSS , , . SMIL, 3 , , 7. , , …
– , - , . CSS, SMIL.
Particles_active ,
.Particles_active .particles{ animation: sparks .7s; }
<set> , , (
set )
<g id="Particles"> <line class="particles" x1="80" y1="162.9" x2="42" y2="59.1"/> ... <line class="particles" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> <set attributeName="class" to="Particles_active" dur=".7s" begin="jump.begin + .5s"/> </g>
:. , , . 3D , . , , .
Adobe Illustrator, . , . - , . ,
d .
, . Shape Shifter.
, , . , Shape Shifter, SVG . Shape Shifter , «» SVG. Illustrator. , . , pathData
, , toValue. . «»
. ,
, , Shape Shifter , , , , . , toValue fromValue .
. ,
<animate attributeName="d" calMode="spline" values=" 1; 2; 1" dur="5s" keySpline=".42,0,.58,1;.42,0,.58,1" repeatCount="indefinite" />
1 – , 2 –. Codepen.
, SVG – , . , ,
<设置>
set标签是animate的简化版本,但不能插值。它用于在特定时间段内即刻更改属性。按照开关原理工作。结果,它忽略了与插值相关的属性,并且不支持累积或相对动画。的值由所述属性仅设置到,属性值,从,通过忽略 <set attributeName="cx" to="200" begin="click" dur="5s" .../>
元素通过单击更改位置,5秒钟后返回其原始位置。如果未指定 dur属性,则元素将保持此状态,直到重新加载文档。否则,它类似于 animate。<animateTransform>
顾名思义,它用于对元素进行各种转换。所有类型的转换都与CSS转换相同。同时使用CSS和SMIL转换,它们将相互覆盖,因此最好使用一件事,或注意不要重叠。如何转型?动画属性是transform。转换模式在type属性中指示,并采用4种类型的值-沿轴的移动,旋转,缩放和移动。平移 -相对于其当前位置移动元素。它采用[x,y]格式的偏移量,其中y 是可选参数 <animateTransform attributeName="transform" type="translate" from="0, -10" to="0, 10" .../>
沿Y轴移动元素以旋转 -相对于旋转中心旋转元素。它以旋转角度和旋转中心的坐标 [deg,x,y]作为值,该中心的坐标是可选的。默认情况下,旋转中心位于SVG文档的左上角 <animateTransform attributeName="transform" type="rotate" from="0, 150, 150" to="45, 150, 150" .../>
围绕坐标为150、150的点旋转45度。此外,还可以使用 transform-origin CSS属性更改旋转中心,该属性中除了坐标之外,还可以指定百分比。默认情况下,百分比是根据整个文档的大小计算的,因此百分比是相对于元素计算的,您需要使用 fill-box值设置 transform-box CSS属性。缩放 -缩放项目。作为值,它采用 [scale]格式的浮点数用于两个轴,或分别用于每个轴 [scaleX,scaleY](1对应于元素的正常大小)。如果您不更改变换框如上所述,该元素是相对于整个文档缩放的。元素周围的空白也会随之改变,因此在视觉上似乎元素已移至侧面 <animateTransform attributeName="transform" type="scale" from="1, 1" to="2, 1" .../>
沿X轴skewX或 skewY 拉伸元素 -相对于该轴移动元素。该值取倾斜角度 [deg]。默认情况下,偏移的中心是左上角,因此具有 transform-box和 transform-origin的相同笑话在这里的工作方式与其他转换一样 <animateTransform attributeName="transform" type="skewX" from="0" to="45" .../> <animateTransform attributeName="transform" type="skewY" from="90" to="0" .../>
一个沿X移位,另一个沿Y移位求和和重新定义变换在 animateTransform中,您仍然可以制作累积动画和相对动画,但是这里的 additive属性的行为不同。在 replace的值中,转换将覆盖所有先前的转换。在总和值中,将转换与前一个求和 <rect transform="skewY(115)" ...> <animateTransform type="translate" from="-10" to="10" additive="replace" .../> <animateTransform type="rotate" from="0" to="90" additive="sum" .../> </rect>
在此示例中,矩形移位将被重新定义为移动和旋转<animateMotion>
需要对元素沿路径的运动进行动画处理。animateMotion支持的属性有生命的,有其自身的3 - 路径,在旋转,关键点。定义轨迹的选项您可以通过几种方式定义运动轨迹-使用熟悉的from,to,by或values属性,新path属性或子<mpath>标记。我列出了增加优先级的方法,我将按照相同的顺序进行说明。属性从,到,通过指示点的坐标,相同的值,但已经以列表的形式 <animateMotion from="0,0" to="50,100" .../> <animateMotion values="0,0; 0,100; 100,100; 0,0" .../>
这种方法的效果可与通常的位移变换相媲美。元素从一个点直线移动到另一个点。在这里,就像animateTransform中一样,坐标是相对的。0,0点不表示文档的左上角,而是目标元素的当前位置。在确定轨迹的其他方法中存在此功能。路径属性指定了一组命令,就像d属性一样。如果在d属性中将命令解释为图形的轮廓,则在path属性中,它们是元素将沿其移动的线。点的坐标也是相对的,因此路径从点0,0开始 <animateMotion path="M 0 0 c 3.4 -6.8 27.8 -54.2 56 -37.7 C 73.3 -27.5 89.6 -5.1 81.9 5.9 c -5.8 8.3 -24.7 8.7 -45.4 -0.4" .../>
这条路径描述了这样一条曲线最后一种方法是使用第三方<path>元素作为path。为此,必须在<mpath>标记中指定指向此元素的链接,并且标记本身必须放置在<animateMotion>内。此选项具有相对坐标的相同功能。此方法的核心是将d属性的值从元素“复制” 到<path>属性。 <path id="movement" .../> ... <animateMotion ...> <mpath href="#movement"/> </animateMotion>
定义路径的元素甚至可能不会出现在文档中。您可以简单地在<defs>中 定义它。相对于轨迹旋转一个元素,可以使用 rotation属性使该元素沿运动方向旋转。它接受3种类型的值: auto, autoreverse和一个数字,以度为单位旋转 <animateMotion rotate="auto" .../>
默认情况下,rotate为0。任何数值都会捕获整个动画中的角度。自动模式自动和自动反向更改与路径相切的元素的旋转角度。它们在切线方向上有所不同。在auto(自动)中,它是前向,而在auto-reverse(自动反向)中,它是后退。如何控制沿路径的运动?轨迹是一条具有起点和终点的曲线,这些点分别由数字0和1表示。曲线上的任何位置都可以由该范围内的数字确定。通过在keyPoints属性中列出这些点,可以定义沿路径的任何类型的移动。但这还不足以控制运动,为此您需要整个属性系统。首先,您需要将calcMode设置为linear或spline。不像其他的标签,animateMotion默认节奏(出于某种原因,动画不希望工作在此模式下)。您还必须指定一个属性。keyTimes。只有完成这些步骤,动画才能正常工作 <animateMotion keyPoints="0.5; 1; 0; 0.5" keyTimes="0; 0.25; 0.75; 1" calcMode="linear" .../>
在该示例中,动画从路径的中间开始,移动到结尾,然后移动到起点,然后在中间再次结束移动聚苯乙烯有分析animateMotion,我碰到的信息一样可以,排序,使CSS。但是,在本文结尾处,我既没有力量也没有渴望处理这个问题。对于发烧友,我只留下文档链接。特别感谢
Bhudh为纠正本文所做的巨大工作