SVG元素可以像HTML元素一样,使用CSS keyframes和animation属性或者CSS transitions来制作各种动画效果。
大多数情况下,一个复杂的动画效果需要组合多种变换效果:旋转、倾斜、缩放以及他们的转换和过渡效果。多数情况下,SVG元素和HTML元素在使用transform
和transform-origin
上是相同的。但它们之间也有不同之处,SVG元素不能使用box model来管理,因此,它没有margin
、padding
、border
或content boxes。
默认情况下,一个HTML元素的transform
原点位于该元素的(50%, 50%)
的地方,这里是元素的中心点。与之不同,SVG元素的transform
原点位于当前用户坐标系统的原点上,这个点是画布的左上角位置。
假设我们有一个<div>
和一个SVG <rect>
元素:
<!DOCTYPE html> … <div style="width: 100px; height: 100px; background-color: orange"> </div> <svg style="width: 150px; height: 150px; background-color: #eee"> <rect width="100" height="100" x="25" y="25" fill="orange" /> </svg>
如果我们在没有改变原点的情况下,都将它们旋转45度,我们将会得到下图的效果(图中的小圆点是它们各种的原点)。
如果我们想根据SVG元素的自身原点,而不是用户坐标系原点来旋转SVG图形该怎么办呢?我们需要使用transform-origin
属性来明确的设置SVG元素的transform
原点位置。
在HTML元素上设置转换原点是一件非常简单的事情:你设置的任何值都是相对于元素的border box。
在SVG中,transform
原点可以使用百分比值或一个绝度值(如像素)来设置。如果你使用百分比值来设置transform-origin
,这个值被设置为相对于元素的bounding box,它包括用于绘制边框的stroke。如果你使用一个绝对值来来设置transform-origin
,那么这个值被设置为相对于用户的当前坐标系统,即SVG的画布。
如果我们要将上例中的<div>
和<rect>
都使用百分比来设置其transform
原点到中心,代码如下:
<!DOCTYPE html> <style> div, rect { transform-origin: 50% 50%; } </style>
得到的结果如下图所示:
必须指出的是,到写这篇文章为止,Firefox浏览器仍不支持使用百分比来设置transform
的原点,这是一个总所周知的bug。因此,目前最好还是使用绝对值来设置transform
的原点。你仍可以在webkit内核的浏览器中使用百分比来设置原点。
下面是一个SVG风车的小例子,我们使用CSS animation来使它不停的旋转。为了使风车绕指定的原点旋转,我们同时使用像素和百分比来设置它的transform
原点。
<svg> <style> .wheel { transform-origin: 193px 164px; -webkit-transform-origin: 50% 50%; -webkit-animation: rotate 4s cubic-bezier(.49,.05,.32,1.04) infinite alternate; animation: rotate 4s cubic-bezier(.49,.05,.32,1.04) infinite alternate; } @-webkit-keyframes rotate { 50% { -webkit-transform: rotate(360deg); } } @keyframes rotate { 50% { transform: rotate(360deg); } } </style> <!-- SVG content --> </svg>
注意,到目前为止,在使用SVG元素的时候,CSS 3D transformations是没有硬件加速的,只是在SVG transform
属性上做了一些优化。但是,Firefox 浏览器对SVG的transforms有一定的加速效果。
SVG路径动画
我们没有办法使用CSS将一个SVG图像转换为另外一个图形。如果你想制作路径变形动画,那么你需要使用javascript。我们建议使用Dmitry Baranovskiy写的Snap.svg。
使用Snap.svg可以很容易的处理一写怪异的问题。
你可以使用CSS来创建动态的画线效果,这个效果你需要知道画线路径的总长度,然后使用SVG的stroke-dashoffset
和stroke-dasharray
属性来制作画线效果,如果你知道画线路径的总长度,可以使用下面的CSS代码来制作这个动画效果:
#path { stroke-dasharray: pathLength; stroke-dashoffset: pathLength; /* transition stroke-dashoffset */ transition: stroke-dashoffset 2s linear; } svg:hover #path{ stroke-dashoffset: 0; }
上面的代码中,当鼠标滑过SVG元素时,路径会向前绘制2秒钟。
在下面的这个例子中,我们使用相同的技术-一个带延迟的CSS transition来制作一个电灯泡通电的效果。
#cable { stroke: #FFF2B1; stroke-dasharray: 4000 4000; stroke-dashoffset: 4000; stroke-width: 4; transition: stroke-dashoffset 8s linear; } svg:hover #cable { stroke-dashoffset: 0; } /* turn lamp on */ .inner-lamp{ fill:grey; transition: fill .5s ease-in 6s; } svg:hover .inner-lamp { fill: #FBFFF8; } /* … */
如果两条线和间隙的值都相等的话,你也可以使用stroke-dasharray: 4000;
来替换stroke-dasharray: 4000 4000
。
有些时候你不知道动画路径的总长度,这时,你可以使用javascript的getTotalLength()
方法来获取路径的长度。
var path = document.querySelector('.drawing-path'); path.getTotalLength(); //set CSS properties up path.style.strokeDasharray = length; path.style.strokeDashoffset = length; //set transition up path.style.transition = 'stroke-dashoffset 2s ease-in-out'; // animate path.style.strokeDashoffset = '0';
上面的代码说明我们可以使用javascript来完成和CSS同样的事情。