CSS3 SVG实现可爱的动物哈士奇和狐狸动画

澳门新葡亰赌995577 4

本文由码农网 –
小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

CSS3 SVG实现可爱的动物哈士奇和狐狸动画

2017/09/28 · CSS,
HTML5 ·
SVG

原文出处: David
Khourshid   译文出处:码农网
– 小峰   

今天,我想向大家展示如何巧妙地使用HTML、CSS排序动画和SVG滤镜把生活中可能最可爱的东西之一——动物画到网页上。我们将探讨绘制动物的两种技术:一种使用纯HTML和CSS,另一种使用内联SVG背景图像。

此演示高度实验性质——动画SVG滤镜目前仅在Chrome中可用。

所涉及的动画也很复杂,因此本教程将重点介绍创建这些动物以及栩栩如生的动作所涉及的不同技术。放飞你的创意,自行创作独特和俏皮的动物动画吧。

话不多说,开始咯!

澳门新葡亰赌995577 1

在线演示
源码下载

今天,我想向大家展示如何巧妙地使用HTML、CSS排序动画和SVG滤镜把生活中可能最可爱的东西之一——动物画到网页上。我们将探讨绘制动物的两种技术:一种使用纯HTML和CSS,另一种使用内联SVG背景图像。

塑造动物外形

演示使用两种不同的技术来创建动物不同身体部位的形状。哈士奇使用CSS
border-radius属性,狐狸使用内联背景SVG图像,因为后者的形状更复杂。

此演示高度实验性质——动画SVG滤镜目前仅在Chrome中可用。

HTML标记

两只动物都使用嵌套的HTML部分对身体部位进行分组。分组的概念对于创造逼真的动画效果非常重要——当头部移动时,眼睛和耳朵也应该保持一起移动,因为它们是长在头上的。

<!– Markup for the fox head –> <div class=”fox-head”>
<div class=”fox-face”> <div class=”fox-ears”> <div
class=”fox-ear”/> <div class=”fox-ear”/> </div> <div
class=”fox-skull”/> <div class=”fox-front”/> <div
class=”fox-eyes”/> <div class=”fox-nose”/> </div>
</div> <!– Markup for the husky head –> <div
class=”husky-head”> <div class=”husky-ear”/> <div
class=”husky-ear”/> <div class=”husky-face”> <div
class=”husky-eye”/> <div class=”husky-eye”/> <div
class=”husky-nose”/> <div class=”husky-mouth”> <div
class=”husky-lips”/> <div class=”husky-tongue”/> </div>
</div> </div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!– Markup for the fox head –>
 
 
<div class="fox-head">
  <div class="fox-face">            
    <div class="fox-ears">
      <div class="fox-ear"/>
      <div class="fox-ear"/>
    </div>
    <div class="fox-skull"/>
    <div class="fox-front"/>
    <div class="fox-eyes"/>
    <div class="fox-nose"/>
  </div>
</div>
 
 
 
<!– Markup for the husky head –>
 
 
<div class="husky-head">
  <div class="husky-ear"/>
  <div class="husky-ear"/>
  <div class="husky-face">
    <div class="husky-eye"/>
    <div class="husky-eye"/>
    <div class="husky-nose"/>
    <div class="husky-mouth">
      <div class="husky-lips"/>
      <div class="husky-tongue"/>
    </div>
  </div>
</div>

每个部分均可以独立移动,并随着其父元素的移动而移动,这样会产生更逼真的效果。不知道你发现没有,尾巴是深深嵌套到其他尾部组件中的。当每个尾巴部分相对于其母体定位,然后旋转相同的量时,就会产生均匀曲线的视觉感。

澳门新葡亰赌995577 2

所涉及的动画也很复杂,因此本教程将重点介绍创建这些动物以及栩栩如生的动作所涉及的不同技术。放飞你的创意,自行创作独特和俏皮的动物动画吧。

用CSS塑造图形

CSS的border-radius属性大量用来塑造哈士奇的形象。对于许多元素要素,需要对每个边界半径进行逐个控制。例如,下面是如何构造哈士奇后腿的代码:

澳门新葡亰赌995577,.husky-hind-leg { // … border-top-left-radius: 35% 100%;
border-top-right-radius: 40% 100%; }

1
2
3
4
5
.husky-hind-leg {
  // …
  border-top-left-radius: 35% 100%;
  border-top-right-radius: 40% 100%;
}

第一个数字表示曲线从顶部/底部边缘开始的深度,第二个数字表示曲线从左/右边缘开始的深度。

其他形状,如前腿,不能单独用border-radius成形,需要使用transform成形:

.husky-front-legs > .husky-leg:before { transform: skewY(-30deg)
skewX(10deg); transform-origin: top right; }

1
2
3
4
.husky-front-legs > .husky-leg:before {
  transform: skewY(-30deg) skewX(10deg);
  transform-origin: top right;
}

一旦图形就位,那么每个元素就能在其父元素中被赋予绝对的基于百分比的位置。这确保每个身体部位的精确放置以及响应性。

话不多说,开始咯!

用SVG塑造图形

至于狐狸,Sass-SVG被用来为每个身体部位创建复杂的SVG形状。SVG图像可以用作背景图像,更好的是,只要它们是基于64或UTF-8编码的,就可以被内联编写(为了最大限度的浏览器支持)。

不过,SVG代码手写起来非常棘手。我使用Adobe Illustrator来创建初始形状:

澳门新葡亰赌995577 3

然后我将每个身体部分保存为SVG图像。SVG代码通过Sass-SVG传输到SCSS样式表。例如,这是狐狸的鼻子:

JavaScript

.fox-nose:before { @ include svg((viewBox: (0 0 168 168))) { // the nose
@ include svg(‘path’, ( fill: $color-nose, d:
‘M83.7,86.7c3.3,0,11.6-3.9,11.6-7.1c0-3.2-9.4-3.2-11.6-3.2c-2.2,0-11.6,0-11.6,3.2
C72.1,82.8,80.4,86.7,83.7,86.7z’ )); // the line connecting the nose to
the mouth @ include svg(‘path’, ( stroke: $color-nose, fill: none, d:
‘M83.7,102.3V86.7’ )); // the mouth @ include svg(‘path’, ( stroke:
$color-nose, fill: none, d:
‘M94.5,104.9c0,0-5.2-2.7-10.8-2.7c-5.6,0-10.8,2.7-10.8,2.7’ )); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.fox-nose:before {
@ include svg((viewBox: (0 0 168 168))) {
    // the nose
   @ include svg(‘path’, (
      fill: $color-nose,
      d: ‘M83.7,86.7c3.3,0,11.6-3.9,11.6-7.1c0-3.2-9.4-3.2-11.6-3.2c-2.2,0-11.6,0-11.6,3.2   C72.1,82.8,80.4,86.7,83.7,86.7z’
    ));
 
    // the line connecting the nose to the mouth
   @ include svg(‘path’, (
      stroke: $color-nose,
      fill: none,
      d: ‘M83.7,102.3V86.7’
    ));
 
    // the mouth
   @ include svg(‘path’, (
      stroke: $color-nose,
      fill: none,
      d: ‘M94.5,104.9c0,0-5.2-2.7-10.8-2.7c-5.6,0-10.8,2.7-10.8,2.7’
    ));
  }
}

这将在url()中生成一个编码的内联SVG字符串,看起来像这样:

.fox-nose:before { background-image:
url(“data:image/svg+xml;,%3Csvg…”); }

1
2
3
.fox-nose:before {
  background-image: url("data:image/svg+xml;,%3Csvg…");
}

由于SVG是一个背景图像,因此它可以被转换和动画化,就像一个HTML元素一样。使用Sass-SVG,Sass
$variables可用于完全控制SVG填充和笔触颜色。

通过内联SVG使狐狸响应起来很简单。viewbox属性值((viewBox:(0 0 168
168)))直接来自SVG文件,但只要保持高/宽比率,那么包含SVG背景图像的元素可以是任意大小。狐狸头部的所有部分都是绝对定位的,具有与.fox-head相同的高度和宽度。

澳门新葡亰赌995577 4

“Squigglevision”和SVG滤镜

Squigglevision是一种通过摆动形状轮廓来模拟手绘动画的动画技术。这使得像狐狸和哈士奇这样的场景看上去更加动态化和手绘化,即使动物在不动的时候也是如此。

SVG有一个称为的滤镜,可以给任何应用了此滤镜的地方“噪声”。结合滤镜以指定像素在每个过滤器中移动的距离。

<svg xmlns=”” version=”1.1″>
<defs> <filter id=”squiggly-0″> <feturbulence
id=”turbulence” basefrequency=”0.02″ numoctaves=”3″ result=”noise”
seed=”0″/> <fedisplacementmap id=”displacement” in=”SourceGraphic”
in2=”noise” scale=”2″/> </filter> <filter
id=”squiggly-1″> <feturbulence id=”turbulence”
basefrequency=”0.02″ numoctaves=”3″ result=”noise” seed=”1″/>
<fedisplacementmap in=”SourceGraphic” in2=”noise” scale=”3″/>
</filter> <filter id=”squiggly-2″> <feturbulence
id=”turbulence” basefrequency=”0.02″ numoctaves=”3″ result=”noise”
seed=”2″/> <fedisplacementmap in=”SourceGraphic” in2=”noise”
scale=”2″/> </filter> <filter id=”squiggly-3″>
<feturbulence id=”turbulence” basefrequency=”0.02″ numoctaves=”3″
result=”noise” seed=”3″/> <fedisplacementmap in=”SourceGraphic”
in2=”noise” scale=”3″/> </filter> <filter
id=”squiggly-4″> <feturbulence id=”turbulence”
basefrequency=”0.02″ numoctaves=”3″ result=”noise” seed=”4″/>
<fedisplacementmap in=”SourceGraphic” in2=”noise” scale=”1″/>
</filter> </defs> </svg>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="squiggly-0">
      <feturbulence id="turbulence" basefrequency="0.02" numoctaves="3" result="noise" seed="0"/>
      <fedisplacementmap id="displacement" in="SourceGraphic" in2="noise" scale="2"/>
    </filter>
    <filter id="squiggly-1">
      <feturbulence id="turbulence" basefrequency="0.02" numoctaves="3" result="noise" seed="1"/>
      <fedisplacementmap in="SourceGraphic" in2="noise" scale="3"/>
    </filter>
    <filter id="squiggly-2">
      <feturbulence id="turbulence" basefrequency="0.02" numoctaves="3" result="noise" seed="2"/>
      <fedisplacementmap in="SourceGraphic" in2="noise" scale="2"/>
    </filter>
    <filter id="squiggly-3">
      <feturbulence id="turbulence" basefrequency="0.02" numoctaves="3" result="noise" seed="3"/>
      <fedisplacementmap in="SourceGraphic" in2="noise" scale="3"/>
    </filter>
    <filter id="squiggly-4">
      <feturbulence id="turbulence" basefrequency="0.02" numoctaves="3" result="noise" seed="4"/>
      <fedisplacementmap in="SourceGraphic" in2="noise" scale="1"/>
    </filter>
  </defs>
</svg>

属性的任何元素。要创建“squigglevision”效果,关键帧动画快速地一次设置一个滤镜

@keyframes squigglevision { 0% { -webkit-filter: url(‘#squiggly-0’);
filter: url(‘#squiggly-0’); } 25% { -webkit-filter:
url(‘#squiggly-1’); filter: url(‘#squiggly-1’); } 50% {
-webkit-filter: url(‘#squiggly-2’); filter: url(‘#squiggly-2’); } 75%
{ -webkit-filter: url(‘#squiggly-3’); filter: url(‘#squiggly-3’); }
100% { -webkit-filter: url(‘#squiggly-4’); filter: url(‘#squiggly-4’);
} }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@keyframes squigglevision {
  0% {
    -webkit-filter: url(‘#squiggly-0’);
    filter: url(‘#squiggly-0’);
  }
  25% {
    -webkit-filter: url(‘#squiggly-1’);
    filter: url(‘#squiggly-1’);
  }
  50% {
    -webkit-filter: url(‘#squiggly-2’);
    filter: url(‘#squiggly-2’);
  }
  75% {
    -webkit-filter: url(‘#squiggly-3’);
    filter: url(‘#squiggly-3’);
  }
  100% {
    -webkit-filter: url(‘#squiggly-4’);
    filter: url(‘#squiggly-4’);
  }
}

注意:这些SVG滤镜目前在Firefox中似乎不起作用,因此可以将这样的滤镜动画视为一种渐进增强处理。

在线演示
 
源码下载

给动物添加动画特效

CSS关键帧不能为我们提供一种方便的排序和组合动画的方法。解决这个问题的最好方法是将动画计划(故事板)作为时间轴,并使用预处理器,如Sass,生成关键帧。

例如狐狸,在概述每个动画应发生的故事板之后,转换和绝对时间偏移(秒)被用于对每个身体部分进行动画处理。以下是SCSS中对狐狸鼻子进行概述的一个例子:

$animations: ( // … ‘nose’: ( // resting position (4s, 5s, 7s):
rotateY(-4deg), // nose down 4.5s: rotateY(-4deg) rotateX(-3deg), // fox
looks left (7.5s, 9s): rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg),
// fox looks right (9.5s, 12s): rotateY(7deg), // fox looks straight
ahead 13s: rotateY(0), ), // … );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$animations: (
  // …
 
  ‘nose’: (
    // resting position
    (4s, 5s, 7s): rotateY(-4deg),
 
    // nose down
    4.5s: rotateY(-4deg) rotateX(-3deg),
 
    // fox looks left
    (7.5s, 9s): rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg),
 
    // fox looks right
    (9.5s, 12s): rotateY(7deg),
 
    // fox looks straight ahead
    13s: rotateY(0),
  ),
 
  // …
);

在这里,$animations是一类Sass
map,其中键是动画的名称(例如“nose”)。每个动画名称的值是另一个map,其中键是以秒为单位的偏移或偏移列表(例如(7.5s,9s)),并且值是每个偏移键的transform属性。

那么,我们怎么把这个map变成@keyframe动画呢?首先,设置全局的$duration:
17s变量——这将是每个动画的总持续时间。然后,使用嵌套的Sass
@each ... in ... 循环,我们可以通过对$animations
map循环为每个动画生成预期的CSS @keyframe声明:

@each $animation-name, $animation in $animations { // keyframe
declaration @keyframes #{$animation-name} { @each $offsets, $transform
in $animation { @each $offset in $offsets { // offset declaration block
#{percentage($offset / $duration)} { // transform property transform:
#{$transform}; } } } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@each $animation-name, $animation in $animations {
  // keyframe declaration
  @keyframes #{$animation-name} {
    @each $offsets, $transform in $animation {
      @each $offset in $offsets {
        // offset declaration block    
        #{percentage($offset / $duration)} {
          // transform property
          transform: #{$transform};
        }
      }
    }
  }
}

这将生成如下所示的关键帧:

@keyframes nose { 14.70588% { transform: rotateY(-4deg); } 23.52941% {
transform: rotateY(-4deg); } 29.41176% { transform: rotateY(-4deg); }
41.17647% { transform: rotateY(-4deg); } 26.47059% { transform:
rotateY(-4deg) rotateX(-3deg); } 44.11765% { transform: rotateX(-3deg)
rotateY(-28deg) rotateZ(-11deg); } 52.94118% { transform: rotateX(-3deg)
rotateY(-28deg) rotateZ(-11deg); } 55.88235% { transform: rotateY(7deg);
} 70.58824% { transform: rotateY(7deg); } 76.47059% { transform:
rotateY(0); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@keyframes nose {
  14.70588% {
    transform: rotateY(-4deg); }
  23.52941% {
    transform: rotateY(-4deg); }
  29.41176% {
    transform: rotateY(-4deg); }
  41.17647% {
    transform: rotateY(-4deg); }
  26.47059% {
    transform: rotateY(-4deg) rotateX(-3deg); }
  44.11765% {
    transform: rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg); }
  52.94118% {
    transform: rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg); }
  55.88235% {
    transform: rotateY(7deg); }
  70.58824% {
    transform: rotateY(7deg); }
  76.47059% {
    transform: rotateY(0); } }

在不使用SCSS的情况下,这些百分比的计算可能非常繁琐。它们代表动画的每个步骤中每个所需时间值相对于总$duration的百分比偏移量。

然后可以将动画应用于它们各自的身体部位,例如animation: nose $duration
none infinite;。每个动画的持续时间都得是一样的,这样它们可以无缝循环。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图