SMIL已经死了! SMIL万岁! SMIL功能替代指南

SVG的本机动画规范SMIL已受到高度重视,因为它为执行SVG动画渲染提供了许多技巧。 不幸的是,在WebKit中对SMIL的支持正在减弱,并且对于Microsoft的IE或Edge浏览器从未(也永远不会)存在。 没有恐惧! 我们已经覆盖了您。 本文探讨了某些特定于SMIL的功能,并深入研究了替代方法,以期获得更长的支持,从而达到相同的效果。

SMIL功能:沿路径运动

SMIL为SVG中逼真的运动提供的最引人注目的东西之一是沿着路径的运动。 现实生活中很少有事物沿直线运动,因此沿着路径运动可以使我们模仿日常生活中看到的事物。 以前,您需要使用path将SVG路径传递到animateMotion中,并定义路径数据。 通过使用xlink:href =”#thingtoanimate”指定要选择动画的元素。

<animateMotion 
  xlink:href="#lil-guy" 
  dur="3s" 
  repeatCount="indefinite" 
  fill="freeze" 
  path="M 25,50 C 37.5,25 37.5,25 50,0 75,50 75,50 100,100 50,100 50,100 0,100 12.5,75 12.5,75 25,50 Z" />

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

另类:CSS

对我们来说幸运的是,沿着路径模块的运动现在正在移入CSS 。 到目前为止,这种支持是微不足道的( 仅适用于Chrome,Opera和Android ):,但Sara Soueidan提议在Edge中采用,并且到目前为止,它已经得到了强有力的支持,在本文发表时,它获得了大约420票以上的支持。 请添加您的声音,以确保将提供此功能。 Firefox的投票在这里
据我所知,在Safari中投票寻求支持会更加个人化。 我注册以填写错误报告,并请求CSS中的运动路径模块作为一项功能。

为了在CSS中沿路径使用运动,您可以将路径数据传递给offset-path属性,如下所示:

.move-me {
  offset-path: path('M3.9,74.8c0,0,0-106.4,75.5-42.6S271.8,184,252.9,106.9s-47.4-130.9-58.2-92s59.8,111.2-32.9,126.1 S5.9,138.6,3.9,74.8z');
}

请参阅CodePen上CSS-Tricks( @ css-tricks )CSS中的“笔与运动路径模块一起 玩”

我从在Illustrator中制作的SVG获取路径数据,然后在SVGOMG中进行优化。

在这种情况下,我要确保它遵循从起点一直到路径终点的路径,并且您可以看到它是一条闭合路径,并由结尾处的小z表示。 这意味着这条路是一条环形路,所以这个怪异的小动物将最终到达他开始的那个地方。 我在关键帧值中设置这些参数,仅指定100%的值,因为默认值设置为零:

@keyframes motionpathguy {
  100% {
    motion-offset: 100%;
  }
}

然后在元素上调用动画:

.move-me {
  animation: motionpathguy 10s linear infinite both;
}
另一种选择:GreenSock的运动轨迹

如果您需要当前最广泛的支持和最灵活的实现,则应使用GreenSock。 GSAP的Bezier-Plugin(默认情况下与TweenMax打包在一起)为非SVG元素提供了对IE7的支持,对SVG提供了对IE9的支持(可用的最广泛的SVG动画支持)。 它就像手机上的大爆炸一样。 我之前在David Walsh博客上写过有关此内容的文章,但这里有一个简短的概述,以及此后出现的一些其他新功能:

最初,您将传递一个值数组:

bezier: {
  type: "soft",
  values:[{x:10, y:30}, {x:-30, y:20}, {x:-40, y:10}, {x:30, y:20}, {x:10, y:30}],
  autoRotate: true
}

但是正如您在此处看到的,您也可以选择自动旋转(或不自动旋转),就像SMIL的旋转一样。 如果您缺少SMIL为旋转的初始位置或旋转角度指定自动反转或auto:n参数的功能,则GSAP允许您使用rotation:90更改旋转角度的数量,或者在需要时使用更有限的控制:

autorotate: [
  first position property, like "x",
  second position property, like "y",
  rotation property, typically "rotation" but can be “rotationY”,
  integer for radians/degrees the rotation starts from like 10,
  boolean for radians or degrees- radians is true
]

在SMIL中,您可以变换路径或组以在对象移动时更改其方向。 在GSAP中,您可以使用autoRotate: false轻松实现此autoRotate: false ,并使用set初始化旋转。 您也可以像使用SMIL一样转换SVG属性本身上的元素,尽管这样做不太优雅,并且在工作时更难以跟踪。

TweenMax.set("#foo" {
  rotation: 90 // or whatever number
});

您还可以将类型设置为thrusoftquadraticcubic 。 有关这些工具的更多文档, 请参见GreenSock API文档 。 的nice值thru是能够影响的元件上弯曲度的量。 如果您将这些点视为要往返的坐标,则曲线将控制这些点之间的路径选择的直接程度。 0将是一条直接路径,1会稍微宽松一些,2会形成一条优美的曲线,3或更高的值会自动缠绕。

见笔演示的弯曲度在使用GreenSock贝塞尔萨拉Drasner( @sdras )上CodePen

最近,GreenSock还公开了传递路径数据(如CSS和SMIL模块)的功能,就像使用本地SMIL一样。 这是对他们的MorphSVG插件的扩展,因此您可以添加该插件,并按以下方式使用它:

TweenMax.to("#lil-guy", 3, {
  bezier: {
    MorphSVGPlugin.pathDataToBezier("#path", {align: "#lil-guy" }), 
    type: "cubic"
  },
  ease: Linear.easeNone,
  repeat: -1
});
<path id="path" d="M 25,50 C 37.5,25 37.5,25 50,0 75,50 75,50 100,100 50,100 50,100 0,100 12.5,75 12.5,75 25,50 Z" fill="none" />

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

默认设置是将我要设置动画的组的左上角(在本例中为#lil-guy )设置为路径轨迹。 这将使其在视觉上看起来未对齐。 所以我将#lil-guy设置为使用中心点,而不是使用TweenLite.set

TweenLite.set("#lil-guy", {xPercent:-50, yPercent:-50});

您还可以通过将对象作为第二个参数传递给该方法来偏移这些路径,并在pathDataToBezier定义offsetXoffsetY -请注意,您可能需要扩展viewBox以使要动画的组或属性不会被裁剪出来。 设置书呆子格式:出于可读性原因,我将对象放在新行上。

// offset the path coordinates by 125px on the x-axis, and 50px on the y-axis:
TweenMax.to("#lil-guy", 3, {
  bezier: {
    values: MorphSVGPlugin.pathDataToBezier("#path", {
      offsetX: 125, 
      offsetY: 50, 
      align: "#lil-guy"
    }),
    type: "cubic"
  },
  ease: Linear.easeNone,
  repeat: -1
});

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

您甚至可以为此定位定义矩阵坐标。

// scale the path coordinates up by 1.25 
// and shift it over 120px on the x-axis 
// and up 30px on the y-axis:
TweenMax.to("#lil-guy", 3, {
  bezier: {
    values: MorphSVGPlugin.pathDataToBezier("#path", {
      matrix:[1.5,0,0,1.5,120,-30], 
      align:"lil-guy"}),
    type: "cubic"
  },
  ease: Linear.easeNone,
  repeat: -1
});

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

另一个选择是将align成员设置为"relative" 。 通过保持每个坐标相对于x:0y:0的位置,它可以防止跳跃。 在先前的笔中,我使用align将机芯与#lil-guy组本身配对。

有关GreenSocks的Bezier插件API中的这一新功能(如本篇文章当天的新内容一样)的更多信息,请查看其文档以及该精彩的解释性视频

SMIL功能:形状变形

以前,您可以将路径数据作为值传递到animate属性中,以使形状变形。 诺亚·布朗(Noah Blon)有一个很好的例子:

见笔Sitepoint挑战SVG和SMIL#1挪亚伦( @noahblon )上CodePen

替代方法:Snap.svg或SVG Morpheus

一些库提供了变形路径或形状值,例如Snap.svgSVG Morpheus ,但要注意的是(即使在SMIL中)形状必须具有相同数量的点,或者变形看起来很糟糕或完全失败。 这在预处理方面令人失望,因为这意味着您必须很好地跟踪所做的工作,或者与设计人员进行良好的协作以确保获得此(有时是任意的)中点数据。 这些额外的点也不必要地膨胀了您的代码。

另一种选择:GreenSock MorphSVG

我强烈建议您使用GSAP的MorphSVG插件,因为它可以用不同数量的点精美地变形形状和路径。 请参阅此网站徽标上的切换按钮,以获取有关实际运行中的变体的演示。 这是另一个例子:

见笔可互换行家萨拉Drasner( @sdras )上CodePen

因为MorphSVG插件会补间路径数据,所以如果需要转换形状,则可以使用其convertToPath选项:

MorphSVGPlugin.convertToPath("ellipse"); 
// or circle, rect, etc

这使我们能够进行非常复杂的形状补间,并且可以改变网络上的所有运动。

该插件提供了一些额外的功能,真正使它脱离了公园。 第一个是实用程序插件findShapeIndex 。 假设您对形状的变形方式不满意(尽管9乘以10,自动预设就可以了)。 您加载了插件(不用担心,因为在生产中不需要它,所以不会增加额外的重量),并且传入两个值:第一个形状的补间ID和第二个形状的ID。 将会弹出一个GUI,您可以在其中切换值,并且它还将自动使用repeat: -1 ,以便在形状之间不断循环。

findShapeIndex("#hex", "#star");
// you can comment out above line to automatically disable findShapeIndex() UI

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

一旦你的附加价值,你会通过shapeIndex的内morphSVG对象:

TweenLite.to("#hex", 1, {morphSVG: { shape: "#star", shapeIndex: 1 }});

这些额外功能中的第二个是插件解析切出路径的能力,这是其他库所没有的。 最后,您还可以重用第一个起始ID(而不是必须存储该路径数据以供重用)。 值得一提的是,当插件首次发布时,这些功能尚不可用,但是GreenSock意识到需要支持,因此将其包含在内。

既然我们不局限于特定数量的点,我们就扩大了产生不同种类效果的可能性。 下面,我抽了一些烟:

CodePen查看 Sarah Drasner( @sdras撰写的《 有烟的笔

SMIL功能:DOM事件

诸如悬停和单击之类的东西很好地融入了SMIL中。 为了开始工作,可以指定begin="click"begin="hover"

<animate 
    xlink:href="#rectblue"
    attributeName="x"
    from="0"
    to="300" 
    dur="1s"
    begin="click"
    values="20; 50"
    keyTimes="0; 1"
    fill="freeze" />

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

另一种选择:JavaScript

有一些本地DOM事件,例如onmouseenteronmouseleave用于悬停并click (例如,单击)。 您可以使用它们进行更改以触发基于JavaScript的动画。

另一种选择:JavaScript + CSS

您可以使用JavaScript更改类名或直接更改CSS样式。 这是可能的:更改animation-play-state以从事件触发器启动动画。

.st0 {
  animation: moveAcross 1s linear both;
  animation-play-state: paused;
}
@keyframes moveAcross {
  to {
    transform: translateX(100px);
  }
}
document.getElementById("rectblue").addEventListener("click", function() {
  event.target.style.animationPlayState = "running";
});

或在jQuery中:

$(".st0").on("click", function() {
  $(this).css("animation-play-state", "running");
});

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

此实现不会像SMIL示例中那样立即将动画重新设置为开始。 如果您想做到这一点,那么上一篇有关CSS-Tricks的文章详细介绍了一些不错的方法。

另一种选择:Greensock

在GSAP中,重新启动更为简单。 我们可以将动画添加到时间轴,将其设置为暂停,然后单击重新启动它。 此实现与您对SMIL的期望有点接近,因为我们不必做任何麻烦的事情,例如克隆/重新插入DOM节点或更改元素上设置的任何属性。

// instantiate a TimelineLite    
var tl = new TimelineLite();

// add a tween to the timeline
tl.to(foo, 0.5, { left: 100 });

$(".st0").on("click", function() {
  tl.restart();
});

SMIL功能:在“ Y”完成后运行“ X”

SMIL还允许进行更复杂的定时事件,例如begin="circ-anim.begin + 1s" 。 当链接动画时,这特别有用。

另类:CSS

在CSS中,我们可以通过在第二个值上设置延迟来链接动画:

.foo {
  animation: foo-move 2s ease both;
}
.bar {
  animation: bar-move 4s 2s ease both; 
  /* the 2 second value corresponds with the length of the iteration of the first. */
}

这种工作方式有点令人讨厌,因为您必须确保记住要更改第一个间隔以及延迟。

另一种选择:CSS预处理

如果我们在(例如)Sass中使用变量,则维护和管理这些间隔会变得容易一些:

$secs: 2s;
.foo {
  animation: foo-move $secs ease both;
}
.bar {
  animation: bar-move 4s $secs ease both; 
}

现在我们知道,如果我们更新一个值,它们将保持同步。

但是,如果我们想在动画完成时,总是发现,JavaScript的提供了这跟一些不错的本地功能animationEnd

$("#rectblue").on("animationend", function() {   
  $(this).closest("svg").find("#rectblue2").css("animation-play-state", "running");     
});
#rectblue2 {
  animation: moveAcross 2s 1s ease both;
  animation-play-state: paused;
}

您可能需要单击重播才能看到以下动画:

见笔SMIL运动路径萨拉Drasner( @sdras )上CodePen

对于延迟,我们可以将其烘焙到元素本身CSS的animation-delay属性中,就像上面一样,或者我们可以使用setTimeout来表示:

setTimeout(function timeoutHandler() {
  // animation goes here, with any language
}, 1000); // wait for a second
另一种选择:Greensock

我最喜欢的选项是添加动画时间轴的有限控制。 我们可以为此使用GreenSock的TimelineLite,可以用几种不同的方式表示:
简单的时间轴:

// instantiate a TimelineLite    
var tl = new TimelineLite();

// add a tween at the beginning of the timeline
tl.to(foo, 0.5, { left: 100 });

// use the position parameter "+=1" to schedule next tween 1 second after the previous tweens end
tl.to(foo, 0.5, { left: 200 }, "+=1");

具有相对标签的时间轴:

// add a label 0.5 seconds later to mark the placement of the next tween
tl.add("myRelativeLabel")
// use the label to specify an animation a second after the 
tl.to(foo, 0.5, { scale: 0 }, "myRelativeLabel+=1");

// or to use to this label for things like interaction 
tl.play("myRelativeLabel");

我更喜欢相对标签,因为您可以选择一个时间点,很多东西会触发或延迟,即使该时间点调整了,您也不必像在CSS中那样进行任何重新计算。 。

时间轴的好处是,您可以在一个位置上很好地控制许多不同的对象,并且可以提供诸如repeatDelay (多次重复之间的延迟)之类的功能。

SMIL提供了repeatDur ,如果您不希望将其作为默认值(例如repeatDur="01:30" ,则可以让您说出重复迭代的时间。 在GreenSock中,您可以加快或减慢时间轴,从而通过timeScale(n)调整重复长度,或将repeat: -1次数设置为repeat: -1 ,否则将设置repeatDur="indefinite"

方便的Dandy更换参考表

既然我们已经深入研究了一些最有用的SMIL特定功能,那么值得注意的是,您可能已经了解了SMIL功能的许多替代品。 我们制作了下表,以便快速参考这些更简单的实现。

SMIL代码 代号 替代技术
关键时间 @keyframes CSS
keySplines 三次贝塞尔曲线 CSS
重新开始 重新开始(); GSAP
calcMode =“离散” 脚步() CSS
去掉 杀();
明确();
clearProps:“全部”
GSAP
冻结 动画播放状态:已暂停 CSS
冻结 暂停(); GSAP
动画填充模式 CSS
repeatCount =“不确定” animation-iteration-count:无限; CSS
repeatCount =“不确定” 重复:-1 GSAP
whenNotActive 在JS中检测动画播放状态 CSS,香草JavaScript或jQuery
animateMotion路径 运动路径 CSS
animateMotion路径 贝塞尔 GSAP
设置动画值(路径变形) 变形SVG GSAP
开始=“悬停” mouseover,mouseenter /
鼠标移开,鼠标离开
jQuery,香草JS
begin =“点击” 点击 jQuery,香草JS
begin =” circ-anim.begin + 1s” 动画延迟:$ vars; 萨斯
begin =” circ-anim.begin + 1s” 时间轴,位置参数ex“ + = 1” GSAP

翻译自: https://css-tricks.com/smil-is-dead-long-live-smil-a-guide-to-alternatives-to-smil-features/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值