拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HTML——SMIL简介

HTML——SMIL简介

SMIL简介

    • 1、SVG语言简介
    • 2、SVG SMIL动画详解
      • 2.1、SVG SMIL动画元素介绍
        • 2.1.1、`<set>`元素
        • 2.1.2、`<animate>`元素
        • 2.1.3、`<animateColor>`元素
        • 2.1.4、`<animateTransform>`元素
        • 2.1.5、`<animateMotion>`元素
        • 2.1.6、自由组合
      • 2.2、SVG SMIL动画属性详解
        • 2.2.1、attributeName
        • 2.2.2、attributeType
        • 2.2.3、from、to、by和values
        • 2.2.4、begin和end
        • 2.2.5、dur
        • 2.2.6、calcMode、keyTimes和keySplines
        • 2.2.7、repeatCount和repeatDur
        • 2.2.8、fill
        • 2.2.9、accumulate和additive
        • 2.2.10、restart
        • 2.2.11、min和max
        • 2.2.12、动画的暂停与播放

SMIL是Synchronized Multimedia Integration Language(同步多媒体集成语言)的首字母缩写,属于XML的一种。换言之,这种语言也是使用一堆尖括号括起来的XML元素标签来实现效果的。下面是一段内容示意:

从事Web开发的前端人员对SMIL通常比较陌生,因为他们平时都是和XHTML打交道,应用SMIL的场景不多。比如,前些年移动、联通等运营商经常发送的彩信[也就是MMS(Multimedia Messaging Service,多媒体消息服务)​]使用的就是SMIL,可以包含视频、音频和图片等,不少多媒体技术人员戏称MMS为“迷你SMIL”(Mini-Me SMIL)。

在其他领域,SMIL的作用和MMS的类似,包括时间定义、布局、动画、视觉渐变和多媒体嵌入,并且SMIL可以和其他XML相结合,迸发出更加强大的生命力。例如,VoiceXML与SMIL相结合,可以在语音浏览器中提供对几个预先提供的页面或幻灯片的顺序阅读;将SMIL与MusicXML相结合可用于创建无限可重组的音乐表序列;将SMIL+VoiceXML或SMIL+MusicXML与RSS或Atom相结合可用于创建具有嵌入式超链接的音频伪播客;将SMIL+SVG与VoiceXML和/或MusicXML相结合可用于创建具有嵌入超链接的自动音频矢量图形动画。

其中,与Web密切相关的就是SMIL+SVG与动画相结合而诞生的SVG SMIL animation,这是SMIL开发组和SVG开发组合作开发的规范,它可以让我们不依赖任何JavaScript代码就能实现炫酷的交互动画效果,很多微信公众号中炫酷的交互阅读体验就是使用SVG SMIL animation实现的。

在详细介绍SVG SMIL动画之前,先要简单介绍一下SVG语言。

1、SVG语言简介

<svg>元素仅仅是SVG语言中一个元素而已,SVG语言共有60多个元素。其中所涉及的知识,简单的非常简单,但是深奥的也确实深奥,比如SVG中的滤镜元素(以fe开头的约30个元素)就需要对图形表现有深刻的理解才能掌握,没有多年持续不断的积累断然是无法消化的。

这些内容并非本书重点,且我也有意向单独出一本介绍SVG的书籍,因此,对于SVG,这里仅简单介绍一下。

SVG是Scalable Vector Graphics(可缩放矢量图形)的首字母缩写,也是XML的一种,规范出来得很早,比CSS还要早。但是,直到IE 9浏览器才开始正式支持它,所以,在早些年的Web开发中SVG并不受待见,后来随着Web技术的发展,以及旧浏览器的淘汰,SVG成为Web开发中极为重要的一门语言。例如,目前,基本上所有Web网站的小图标方案都是采用SVG实现的,并有诸多与之配套的工具。

另外,SVG还在动效表现和特效实现上大放异彩,前者需要配合JavaScript和CSS实现,后者使用SVG滤镜。在过去,SVG的图形效果只能通过HTML属性实现,例如实现一个有边框的圆形效果:

上面的代码表示在一个300像素宽、150像素高的SVG画布中,绘制一个圆形,圆心坐标为(100, 50),半径为40像素,边框为黑色,边框宽度为2像素,填充色为红色。效果如图所示。


现在,Web愈发开放,上图中的图形效果可以直接使用CSS进行设置,例如:

因此,对于常规的SVG图形效果,你就当作普通的HTML学习即可,没有什么难度。对SVG就介绍这么多,接下来,我们好好介绍SVG SMIL动画。SVG SMIL动画可以实现以下这些效果:

  • 动画元素的数值属性(X, Y, …)。
  • 动画属性变换(平移或旋转)​。
  • 动画颜色属性。
  • 沿着运动路径运动。
  • 支持点击交互动画。

虽说目前的Web技术可以实现上述所有效果,但是这些效果要么需要借助CSS代码,要么需要借助JavaScript代码,而SVG SMIL动画不需要借助任何CSS和JavaScript代码,只需要在页面添加几个<animate>元素即可。例如,有下面这段SVG代码:

其中使用了<animateTransform>元素,该元素是专门用来实现SVG SMIL动画的。这里可以实现一个不断旋转的“马”字效果,动画分解示意效果如图所示。


可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse.svg访问来体验其效果。

正因为SVG SMIL动画是纯HTML语言的,所以它才能在诸如微信公众号这样的编辑器中使用,而不会担忧引发安全问题(如果编辑器保留CSS和JavaScript,势必会影响公众号页面的交互与渲染)​。

2、SVG SMIL动画详解

2.1、SVG SMIL动画元素介绍

SVG SMIL动画的元素其实只有5个,分别如下:

  • <set>
  • <animate>
  • <animateColor>
  • <animateTransform>
  • <animateMotion>

它们可以分别实现不同类型的动画。

2.1.1、<set>元素

set的意思是设置,此元素没有动画效果。大家可能会有疑问,它没有动画效果,怎么会是SVG SMIL动画五大元素成员之一呢?

<set>元素虽然不能触发连续的动画,但是,其还是可以实现基本的延迟功能的,即它可以在特定时间之后修改某个属性值。例如,有如下所示的代码:

此时,​“马”这个文字图形会在3秒之后从横坐标160的位置移动到60的位置。可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-set.svg访问来体验其效果。

这里出现的attributeName、attributeType等属性,后面会统一讲解。

2.1.2、<animate>元素

它是基础动画元素,实现单属性的动画过渡效果。例如,下面这段代码可以实现一个不断水平移动的“马”的动画效果。


可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-animate.svg访问来体验其效果。

2.1.3、<animateColor>元素

一看就知道它是实现颜色动画的。不过,<animate>元素同样可以实现颜色动画,因此,此属性已经被废弃。

2.1.4、<animateTransform>元素

此元素就是最开始案例中使用的元素。一看就知道它是用来实现transform变换动画效果的。知识是一脉相承的,这里的transform变换与CSS的transform变换是一个原理。例如,要实现一个尺寸不断放大的“马”图形效果,可以这样设置:

可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-scale.svg访问来体验其效果。

这里的type属性值可以是scale、rotate、translate、skewX、skewY,分别表示缩放、旋转、平移、X轴倾斜、Y轴倾斜。

2.1.5、<animateMotion>元素

<animateMotion>元素可以让SVG图形沿着任意的路径运动,例如下面这个案例:


其中,<path>元素用于描述运动的路径,和最终的动画效果(见下图)无关。

截图是静态的,无法展现动画的精髓,推荐通过在浏览器中输入https://www.htmlapi.cn/assets/horse-motion.svg访问来体验其效果。

不过上面的效果有一个问题,那就是这个“马”行走的姿势有点假,明明“路”是崎岖的,但马儿的运动方向一直都是水平的,并不符合物理学规律。别担心,我们可以略做处理,让“马”的表现更真实:

通过设置rotate=“auto”,可以让物体按照路径的切线方向运动,自然表现就更加真实了,如图所示。

推荐通过在浏览器中输入https://www.htmlapi.cn/assets/horse-motion-rotate.svg访问来体验其效果。

不过,有时候SVG中的图形可能是圆形、方形这样有规律的图形,是使用<circle>元素和<rect>元素渲染的,而<animateMotion>元素的运动路径只能使用path属性,此时,就需要转换,也就是将任意的SVG图形元素转换为用path属性表示,这并不难,大家可以访问此项目以了解相关的实现:https://gitee.com/zhangxinxu/svg-to-path。

2.1.6、自由组合

实际的动画效果不可能总是通过一个属性修改的。比如,位置和透明度同时变化时,怎么办呢?简单,直接组合就可以了,如以下代码:

其实现的是马儿入山影无踪的意境效果,连续截图见下图。


可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-combine.svg访问来体验其效果。

至此,体验SVG SMIL动画效果的旅程就结束了。如果你单纯想感受一下、开阔一下眼界,那么以上内容就足够了;如果你打算深入学习SVG SMIL动画,那么下面的属性详解则不容错过。

2.2、SVG SMIL动画属性详解

SVG SMIL动画的属性很多,不过理解成本都不高。

2.2.1、attributeName

attributeName属性表示要变化的元素属性名称,可以是:

  • 元素直接暴露的属性。例如,对于本文反复出现的「马」对应的<text>元素上的x,y或者font-size。
  • CSS属性。例如,透明度opacity属性。
2.2.2、attributeType

attributeType属性支持CSS、XML、auto三个固定的值,作用是表明attributeName属性值的列表。其中,x、y、transform属于XML,opacity属于CSS,auto为默认值,是自动判别(实际上是先作为CSS类别处理,如果发现不认识,则直接按XML类别处理)的意思。因此,如果你不确信某个属性是XML类别还是CSS类别,我的建议是不设置attributeType属性值,直接让浏览器自己去判断,几乎无差错。

不知大家有没有和我一样的疑问:​“既然浏览器可以自己判断属性类别,那么这个属性还有什么意义吗?​”我猜测,针对某些属性,XML能起作用,CSS也能起作用,例如font-size,此时就需要明确一下归属。

2.2.3、from、to、by和values

上面4个属性属于同一个家族,是最具哲理的一个家族。它们解决的是非常有哲理的问题:你从哪里来?要到哪里去?……

  • from="<value>":动画的起始值。
  • to="<value>":指定动画的结束值。
  • by="<value>":动画的相对变化值。
  • values="<list>":用分号分隔的一个或多个值,可以看成动画的多个关键值点。

from、to、by和values属性虽然属于同一个家族,但是它们之间还是有制约关系的,有以下一些规则:

  • 如果动画的起始值与元素的默认值是一样的,则from属性可以省略。
  • (不考虑values属性)to和by两个属性至少需要有一个出现,否则没有动画效果。to表示绝对值,by表示相对值。以位移为例,如果from值为100,to值为160,则表示移动到160这个位置,但是如果by值为160,则表示移动到100+160=260这个位置。
  • 如果to属性和by属性同时出现,则by属性无效,只识别to属性。
  • 如果to、by、values 3个属性都没被设置,则自然没有动画效果。如果任意(包括from属性)一个属性的值不合法,则从规范上说是没有动画效果的。但是,据我测试,在FireFox浏览器下确实如此,但是在Chrome浏览器下特意做了容错处理。例如,针对本来是数值的属性,写了一个诸如a这个不合法的值,其会被当作0来处理,动画效果依然存在。
  • values属性可以是一个值或多个值。根据我在Chrome浏览器下的测试,它是一个值的时候是没有动画效果的;它是多个值时有动画效果。当values值被设置并能识别时,from、to、by的值都会被忽略。那么,values属性是干什么的呢?别看名字挺大众的,其还是有些“功力”的。我们实现动画不可能就是单纯地设置为从a位置到b位置,有时候需要去c位置过渡一下。此时,实际上有三个动画关键点,而from、to、by属性只能驾驭两个,这就到了values属性大显身手的时候了!例如,下面这个聪明的马儿来回跑的效果,就是通过values属性设置三个动画关键点实现的:

    可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-values.svg访问来体验其效果。
2.2.4、begin和end

begin属性指动画开始的时间,看上去很简单,实际上并没有看上去的那么简单,上面出现的beigin="3s"只是最简单、最基本的表示。

begin属性的定义是分号分隔的一组值,单值只是其中的情况之一。例如,beigin="3s;6s"表示的是3s后动画走一下,6s时动画再走一下(如果之前动画没走完,则会立即停止,从头开始)​。所以,当一次动画时间为3s,即dur=“3s”,同时没有设置repeatCount属性时,我们可以看到动画似乎连续执行了2次。

既然这里提到了时间,就顺势简单讲一下SVG animation中的时间表示(也适用于dur属性和end属性)​。常见的单位有"h"、“min”、“s”、“ms”。

时间值支持的格式和规则相当复杂,不过我们只需要了解一下最常见的基本使用方法就足够了。

上面的单位含义都是英文单位的缩写。例如h表示小时(hour)。

时间值支持小数写法,因此,90s也可以用1.5min表示。时间值还支持hh:mm:ss这种写法,因此,90s也可以用01:30表示。

还有一点,十进制的小数值是秒的浮点定义,就是说如果begin="1.5"没有单位,这里的小数点表示秒,也就是1.5s的意思。所以,上面多次出现的beigin="3s"也可以简写为beigin=“3”。我测试了一下,FireFox和Chrome浏览器对其都是支持的。

begin的值除普通value外,还有下面这些类别的value:

  • offset-value
    offset-value表示偏移值,数值前面有+或-,偏移计算是相对于begin值而来的。

  • syncbase-value
    syncbase-value基于同步确定的值,语法为[元素的id].begin/end+/-时间值。就是说借用其他元素的begin值再进行加减,可以准确实现两个独立元素的动画级联效果。看完下面的例子,你一定会豁然开朗,对上面的offset-value也会有一定的认知。代码如下:

    于是,就实现了一个马儿折线跑的效果,先横向移动,再无缝纵向移动,大家可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-animate-x-y.svg访问来体验其效果。

    可以看到,后面attributeName为y的元素的begin值是x.end。x.end中的x就是上面animate元素的id值,而end是动画元素都有的一个属性,表示动画结束的时间。因此,begin="x.end"的意思就是,当id值为x的元素动画结束的时候,执行动画,类似于PowerPoint动画的“上一个动画之后”的选项。

    当然,我们还可以增加一些偏移值,例如begin=“x.end-1s”,就表示id值为x的元素动画结束前一秒开始纵向移动。

  • event-value
    event-value表示与事件相关联的值,类似于PowerPoint动画的“点击执行该动画”​。语法是[元素的id].[事件类型]+/-时间值。举个例子,假设有下面这段SVG代码:

    则会看到图所示的渲染效果,此时,点击图中黑色的圆,马儿就会自己跑起来!

    可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-click-run.svg访问来体验其效果。

    代码的关键点就是begin=“circle.click”。其中circle为<circle>元素(黑色圆)的id值,click表示点击事件。如果你想实现点击圆2秒钟后马儿开始跑,很简单,加上偏移时间就可以了—begin=“circle.click+2s”。

    需要注意的是,这类与事件关联的SVG需要内联在页面中,否则无论是click还是其他值都不会有效果。

  • repeat-value
    repeat-value指重复多少次之后做什么,语法为[元素的id].repeat(整数)+/-时间值。举个例子,实现马儿水平运动2次之后,斜向运动的效果,SVG代码如下:


    可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-repeat-value.svg访问来体验其效果。

    其中,begin="x.repeat(2)"指的是id值为x的元素的动画重复2次后执行。

  • accessKey-value
    accessKey-value用于定义快捷键,即按下某个键动画开始,语法为accessKey(“character”)​。character表示快捷键所在的字符。举个例子,按下s键动画开始。SVG代码如下:

    理论上,按下键盘上的字母“s”​,动画就会执行。但是,据我测试,在Chrome浏览器(版本120)下是没有效果的,Firefox浏览器很早之前的版本有效果,但是现在也没效果了,原因不详。

    大家若有兴趣,可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-accesskey-value.svg访问来看看自己当前的浏览器在按下“s”键后,是否有动画出现。

  • wallclock-sync-value
    wallclock-sync-value指真实世界的时钟时间定义。时间语法基于在ISO8601中定义的语法,如1997-07-16T19:20:30.45+01:00,这个不太符合国内人的书写习惯。

  • indefinite
    “indefinite”就是指字符串值,表示“无限等待”​。据说需要beginElement()方法触发或者指向该动画元素的超链接(SVG中的a元素)才可以。下面的代码是beginElement()方法触发的例子:

    此时,点击“马”字图形,​“马”就会运动起来。不过,我还是推荐使用超链接来触发点击运动,因为无须任何JavaScript代码参与,案例代码如下:

    此时,就会看到下图所示的渲染效果。随后,点击红色的文字“点击我”​,就可以看到下面的“马”运动起来了。


可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-begin-link.svg访问来体验其效果。

最后,附上规范上出现的一段文字:

If no begin is specified,the default value is “0”-theanimation begins when the document begins.If thereis any error in the argument value syntax for begin,thedefault value for begin will be used.

它的意思是,没有begin属性值或者begin属性解析异常,都当作0处理。

目前讲述的都是begin属性,至于end属性,由于其与begin属性除名字和字面含义不一样外,其值的种类与表意都是一样的,这里就不重复讲述了。

2.2.5、dur

dur属性比begin属性简单,它的值只有后面两种:常规时间值和"indefinite"。

常规时间值就是3s之类的正常值;“indefinite"指无限等 待。试想一下,动画时间无限,实际上就是动画不执行的意思。因此,将dur属性值设置为"indefinite”,与没有设置dur属性或dur属性解析异常的效果是一样的。

2.2.6、calcMode、keyTimes和keySplines

calcMode、keyTimes和keySplines 3个属性用来控制动画是匀速的,还是先快后慢的,抑或是先慢后快的。

  • calcMode
    calcMode属性支持4个值:discrete、linear、paced和spline,中文意思分别是离散、线性、踏步、样条。

    • discrete:表示从from值直接跳到to值。
    • linear:表示除<animateMotion>元素以外的元素的calcMode默认值。动画从头到尾的速率都是一致的。
    • paced:表示通过插值让动画的变化步调平稳均匀。仅支持线性数值区域内的值,这样点之间“距离”的概念(如position、width、height等)才能被计算。如果paced被指定,任何keyTimes值或keySplines值都会无效。
    • spline:表示插值定义贝塞尔曲线。具体的曲线控制点是被定义在keyTimes属性中的,而每个时间间隔控制点是由keySplines属性定义的。
  • keyTimes="<list>"
    keyTimes表示关键时间点,<list>表示分号分隔一组值。这里有一些约定的规则:首先,keyTimes值的数目要和values一致,如果是from/to/by动画,keyTimes必须有两个值。其次,对于linear和spline动画,第一个数字是0,最后一个是1。最后,每个连续的时间值必须比它前面的值大或者两者相等。

    在paced模式下,keyTimes会被忽略;如果keyTimes被定义错误和dur属性值为indefinite,它也会被忽略。

  • keySplines="<list>"
    keySplines表示的是与keyTimes相关联的一组贝塞尔控制点(默认为0 0 1 1)​。每个控制点都使用4个浮点值表示:x1 y1 x2 y2,一些常见的keySplines属性值和对应的运动函数曲线见图(示意图取自W3C官方文档)​。

    另外,只有在spline模式下keySplines属性才有用,也是以分号分隔的,值的范围为0~1,总是比keyTimes少一个值。如果keySplines值不合法或个数不对,则没有动画效果。

    专业的术语容易让人“云里雾里”​,有必要通过案例进一步加以说明,如下是4个SVG的代码,只展示重要部分:


    其效果大家可以通过在浏览器中输入https://www.htmlapi.cn/13/1-1.html访问来体验。

进入页面,可以看到4匹马你追我赶的精彩画面,其中某一时间的截图画面如图所示。

不妨以最后一个SVG为例加以说明,最终的动画效果是由values、keyTimes和keySplines三个属性相互配合完成的。values属性确定动画的关键位置,keyTimes属性确定到这个关键点需要的时间,keySplines属性确定的是每个时间点段之间的贝塞尔曲线,也就是具体的缓动表现。这和CSS中的transition动画颇为相似,不过也有区别,如果将SVG中的动画属性换算成CSS transition动画的属性,那么对应的values值只有两个,keyTimes只能是0和1,贝塞尔曲线只有一个,曲线函数要么是ease、linear等关键字,要么就是cubic-bezier()函数。而SVG SMIL动画可以指定任意多个动画的起止过程和每个区段的运动细节,由此可见,SVG SMIL动画比CSS动画强一些。

2.2.7、repeatCount和repeatDur

repeatCount表示动画执行次数,可以是合法数值或者"indefinite"(无限等待)​。

repeatDur定义重复动画的总时间,可以是普通时间值或者"indefinite"(无限等待)​。

上述动画只执行3个完整动画和一个1/3个动画,因为repeat总时间只有10s。

2.2.8、fill

fill表示动画间隙的填充方式,支持的值有freeze和remove。其中,remove是默认值,表示动画结束直接回到开始的地方。freeze表示动画结束后像是被冻住了,元素保持动画结束之后的状态。

2.2.9、accumulate和additive

accumulate是累积的意思,支持的值有none和sum,默认值是none。如果accumulate的值是sum,则表示将动画结束时的位置作为下次动画的起始位置。

additive用于控制动画是否附加,支持的值有replace和sum,默认值是replace。如果additive的值是sum,则表示动画的基础知识会附加到其他低优先级的动画上。

举两个例子,例子1:


这里轮到第二个动画的时候,路径是从第一个动画路径结束的地方开始的,于是,三个动画完美无缝地连接起来了。

例子2:

这里有两个类型不同的变换动画,一个是scale放大,另一个是rotate旋转。通常来说,由于它们共用同一个attributeName,因此效果是互相覆盖的,不过由于这个例子设置的是additive=“sum”,也就是动画效果是累加的,而不是替换的,于是,就可以实现一边旋转一边放大的效果。

大家可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-animate-sum.svg访问来体验其效果。

2.2.10、restart

restart属性诞生的背景如下:很多动画的触发与事件相关,例如,点击某个圆,马儿就跑。而且,似乎每点一次,马儿就跑一下。现在存在这种情况,希望马儿只跑一次,之后再点击就没有反应。这种需求的出现迫使restart属性出现了。它支持的值有always、whenNotActive、never。

always是默认值,表示总是,也就是点一次圆,马儿跑一下。whenNotActive表示动画正在进行的时候,是不能重启动画的。never表示动画是一波流。

这些属性值都很好理解,就不举例了。

2.2.11、min和max

min属性和max属性表示动画执行的最短时间和最长时间,支持的值为时间值和"media"(媒介元素有效)​,max属性还支持indefinite.

2.2.12、动画的暂停与播放

SVG SMIL动画均是可以随时暂停与播放的,假设变量svg表示的就是当前
<svg>DOM元素,则SVG SMIL动画的暂停和重启动都可以使用下面的语法来实现:


例如,下面这个SVG示例,点击就会暂停,再点击就会重新运动。

大家可以通过在浏览器中输入https://www.htmlapi.cn/assets/horse-play-pause.svg访问来体验其效果。

返回列表