经典卡通如何启发现代CSS动画技术

本文探讨了如何从汉纳-巴伯拉经典卡通动画的有限技术中汲取灵感,通过CSS实现分层、循环帧和微妙动作,为现代网页设计注入个性与活力,提升用户体验。

粉碎动画第一部分:经典卡通如何启发现代CSS

你是否曾想过早期卡通动画的局限性如何与当今的网页设计相关联?从循环背景到最小帧变化,这些复古动画技术与现代CSS有着惊人的相似之处。在这篇文章中,先锋作者和网页设计师Andy Clarke展示了他如何将这些原则应用到艾美奖获奖作曲家Mike Worth的新网站上,使用CSS制作引人入胜且有趣的动画,将他的世界带入生活。

浏览器制造商很快就为CSS添加了运动能力。首先是简单的:hover伪类,然后是两种状态之间的过渡。接着是跨一组@keyframes改变状态的能力,最近还有将关键帧与滚动位置链接的滚动驱动动画。

即使有了这些新增功能,CSS动画仍然相对基础。它们让我想起了我小时候在电视上观看的汉纳-巴伯拉动画系列。

这些动画短片的预算远低于真人或动画电影,也远低于William Hanna和Joseph Barbera在为米高梅卡通公司制作《猫和老鼠》短片时的预算。这意味着动画师需要开发技术来应对成本限制和当时的技术限制。

他们每秒使用更少的帧数和更少的单元格。他们不是为每一帧使用不同的图像,而是将每一帧重复几次。他们通过缩放和叠加额外元素来尽可能频繁地重复使用单元格,以构建新场景。他们保持身体基本静止,叠加眼睛、嘴巴和腿部来创造说话和行走的幻觉。这些限制并没有降低这些卡通的质量,反而创造了一种魅力,这在最近更大预算和技术更先进的作品中常常缺乏。

汉纳-巴伯拉动画师开发的简单高效技术可以使用CSS实现。现代布局工具允许网页开发者分层元素。可缩放矢量图形(SVG)可以包含多个帧,开发者无需借助JavaScript;他们可以使用CSS来改变元素的不透明度、位置和可见性。但这样做的原因是什么?

动画将静态体验带入生活。它们可以通过引导人们的行动并在与设计互动时取悦或惊喜他们来改善可用性。经过仔细考虑,动画可以加强品牌形象并帮助讲述品牌故事。

介绍Mike Worth

我最近一直在为艾美奖获奖游戏作曲家Mike Worth制作一个新网站。他聘请我创建一个大胆的复古风格设计,展示他的作品。我在整个网站上使用了CSS动画,以在他受众浏览网站时取悦和惊喜他们。

Mike喜欢80年代和90年代的动画——尤其是迪士尼的《唐老鸭俱乐部》。不出所料,我对卡通的品味可以追溯到更远的60年代汉纳-巴伯拉节目,如《达斯塔德利和穆特利在他们的飞行机器》、《史酷比》、《佩内洛普·皮特斯托普的危险》、《疯狂赛车》,当然还有《瑜伽熊》。

因此,为了解释这个动画时代如何与CSS相关,我选择了1961年首次播出的《瑜伽熊秀》的一集“Home Sweet Jellystone”。在这个故事中,Ranger Smith继承了一座豪宅,并且(剧透警告)离开了Jellystone。

剖析运动

在这一集中,汉纳-巴伯拉的技术在邮递员带着电报给Ranger Smith时变得明显。摄像机横向平移背景艺术家Robert Gentle的风景画,以创造邮递员正在移动的幻觉。

当场景持续时间超过Robert Gentle风景画的单次平移时,背景会循环,灌木和树木反复出现。

这可以使用单个元素和改变其背景图像位置的动画来重新创建:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@keyframes background-scroll {
  0% { background-position: 2750px 0; }
  100% { background-position: 0 0; }
}

div {
  overflow: hidden;
  width: 100vw;
  height: 540px;
  background-image: url("…");
  background-size: 2750px 540px;
  background-repeat: repeat-x;
  animation: background-scroll 5s linear infinite;
}

尽管执行得很漂亮,但Robert Gentle的背景画通常非常简单。豪宅的内部背景快速掠过,以创造Ranger Smith冲过它的幻觉,因此它需要很少的细节。

运动的节约对于廉价高效地制作这些动画短片至关重要。邮递员的摩托车弹跳,只有他的头部位置和面部表情发生变化,这增加了一丝微妙的真实感。

同样,在Ranger Smith穿过他的豪宅的整个行走周期中,只有他的面部表情和腿部位置发生变化。他身体的其余部分保持静止。

在我为他网站设计的一个废弃场景中,可以看到我为Mike Worth创建的猩猩冒险吉祥物驾车穿越景观。

我直接借鉴了汉纳-巴伯拉的弹跳和滚动技术,通过使用两个关键帧动画:background-scroll和bumpy-ride。无限滚动的背景工作原理与之前相同:

1
2
3
4
@keyframes background-scroll {
  0% { background-position: 960px 0; }
  100% { background-position: 0 0; }
}

我通过动画改变关键帧的平移值来创造颠簸行驶的外观:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@keyframes bumpy-ride {
  0% { translate: 0 0; }
  10% { translate: 0 -5px; }
  20% { translate: 0 3px; }
  30% { translate: 0 -3px; }
  40% { translate: 0 5px; }
  50% { translate: 0 -10px; }
  60% { translate: 0 4px; }
  70% { translate: 0 -2px; }
  80% { translate: 0 7px; }
  90% { translate: 0 -4px; }
  100% { translate: 0 0; }
}

figure {
  /* ... */
  animation: background-scroll 5s linear infinite;
}

img {
  /* ... */
  animation: bumpy-ride 1.5s infinite ease-in-out;
}

正如Michelle Barker在2021年在Smashing Magazine上写道:

“在处理网页上的运动时,重要的是要考虑并非每个人都能以相同的方式体验它。对某些人来说可能感觉流畅和光滑的东西,对其他人来说可能是烦人或分散注意力的——或者更糟,引起恶心甚至导致癫痫发作。”

您可以通过在有人在浏览器中选择减少运动时使用prefers-reduced-motion媒体查询来关闭动画来防止这种情况发生:

1
2
3
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }
}

重用元素

由于每集的预算和制作时间有限,William Hanna和Joseph Barbera创建了一个简化的流程来制作他们的动画。他们每集使用少至2,000个单独绘图和仅几个背景画,通常在多集中重复使用它们。

观看这一集,你会看到这些树木在“Home Sweet Jellystone”中反复出现。在瑜伽和Boo-Boo身后的轨道上,在灌木丛中,以及在这个Boo-Boo特写中放大:

动画师还经常将这些前景元素分层到这些背景画上,以创建各种新场景:

在我从Mike Worth网站删除的场景中,我将这些岩石引入前景,为动画增加深度:

如果我使用位图图像,这只需要一个额外的图像:

1
2
3
4
<figure>
  <img id="bumpy-ride" src="..." alt="" />
  <img id="apes-rock" src="..." alt="" />
</figure>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
figure {
  position: relative; 

  #bumpy-ride { ... }

  #apes-rock {
    position: absolute;
    width: 960px;
    left: calc(50% - 480px);
    bottom: 0;
  }
}

如果我继续开发这个场景,我可能会为那些岩石添加一个较慢的滚动动画,以引入视差效果,从而获得更大的真实感。

循环帧创造运动

为了满足有限的预算和制作计划,汉纳-巴伯拉的动画师仔细规划了他们的动画,并巧妙地只动画特定元素。虽然头部和面部表情使角色说话,腿部变化使它们行走,但大多数角色的身体保持相对静止。因此,在Ranger Smith行走和说话穿过他的小屋的整个场景中,只有他的脸和腿部被动画化:

同样,当护林员阅读他的电报时,只有他的眼睛和嘴巴移动:

如果你想知道为什么Ranger Smith和瑜伽熊都戴领子和领带,这是为了模糊他们动画头部和面部与静态身体之间的界线:

SVG提供了惊人的性能,并且在动画元素时也提供了极大的灵活性。能够将一个SVG嵌入另一个SVG中,并使用CSS操作组和其他元素,使其成为动画的理想选择。

“我复制了汉纳-巴伯拉如何使Ranger Smith和其他角色的嘴巴移动,首先包括一个包含护林员身体和头部的组,这些在整个过程中保持静态。然后,我添加了另外六个组,每个组包含他嘴巴移动的一帧:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<svg>
  <!-- 静态元素 -->
  <g>...</g>

  <!-- 动画帧 -->
  <g class="frame-1">...</g>
  <g class="frame-2">...</g>
  <g class="frame-3">...</g>
  <g class="frame-4">...</g>
  <g class="frame-5">...</g>
  <g class="frame-6">...</g>
</svg>

我使用CSS自定义属性来定义角色嘴巴移动的速度和动画中的帧数:

1
2
3
4
:root {
  --animation-duration: 1s;
  --frame-count: 6;
}

然后,我应用了一个关键帧动画来显示和隐藏每一帧:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@keyframes ranger-talking {
  0% { visibility: visible; }
  16.67% { visibility: hidden; }
  100% { visibility: hidden; }
}

[class*="frame"] {
  visibility: hidden;
  animation: ranger-talking var(--animation-duration) infinite;
}

最后设置一个延迟,使每一帧在正确的时间可见:

1
2
3
4
5
6
7
8
9
.frame-1 {
  animation-delay: calc(var(--animation-duration) * 0 / var(--frame-count));
}

/* ... */

.frame-6 {
  animation-delay: calc(var(--animation-duration) * 5 / var(--frame-count));
}

与Mike Worth合作

当Mike Worth和我坐下来讨论合作时,我们都明白既没有预算也没有时间为他的网站制作一个简短的动画卡通。我们也知道视频将是完全动画制作的正确格式,但我们渴望探索CSS如何将原本是静态图像的内容带入生活。因此,这就引出了为什么以及何时使用CSS动画的问题。

环境动画

微妙的环境动画有助于网站的氛围,并帮助讲故事,而不会分散其内容或功能。

对于Mike Worth的关于页面插图,我将光束照射到石板上,为原本平坦的图像增加深度。在我的SVG中,我为光添加了一个路径,并将其不透明度降低到.25:

1
2
3
4
<svg>
  <!-- ... -->
  <path class="light-shaft" fill="#F1DCA9" opacity=".25" d=""/>
</svg>

然后,我定义了一个SVG过滤器来模糊我的光束边缘,并将其链接到我的路径:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<defs>
  <filter id="light-shaft" width="100%" height="100%" x="0" y="0" filterUnits="objectBoundingBox">
  <feGaussianBlur in="SourceGraphic" stdDeviation="20"/>
  </filter>
</defs>

<svg>
  <!-- ... -->
  <path class="light-shaft" filter="url(#light-shaft)"  />
</svg>

最后,我添加了一个微妙的环境动画,旋转光束,创造更自然的感觉:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@keyframes shaft-rotate {
  0% { rotate: 2deg; }
  50% { rotate: -2deg; }
  100% { rotate: 2deg; }
}

.light-shaft {
  animation: shaft-rotate 20s infinite;
  transform-origin: 100% 0;
}

交互动画

就像:hover伪类在有人与元素交互时提供有价值的视觉反馈一样,CSS动画可以在人与设计之间建立更深的联系。

我在Mike Worth的评论页面插图中包含了一个复活节彩蛋交互。大红按钮打开和关闭台灯,这让Mike的猩猩吉祥物非常懊恼,他正试图研究他的地图。为了实现这一点,我在SVG插图上应用了一个data-属性:

1
2
3
<svg  data-lights="lights-on">
  <!-- ... -->
</svg>

并为任何好奇的访问者添加了一个红色按钮:

1
2
3
4
5
<a href="javascript:void(0);" id="light-switch" title="Lights on/off">
  <path fill="#0a0908" d="..."/>
  <ellipse fill="#9c1621"  />
  <path fill="#fff" d="..."/>
</a>

当有人按下那个红色按钮时,灯熄灭,这是通过将SVG的data-属性值从lights-on更改为lights-off来实现的。

插图中的几个元素在台灯打开时会亮起。为了实现这一点,我为这些特定项目应用了一个类值:

1
<path class="lamp-glow" />

并使用data-属性值在有人按下灯按钮时切换发光:

1
2
3
4
5
6
7
8
9
[data-lights="lights-on"] .lamp-glow {
  opacity: 1;
  transition: opacity .25s linear;
}

[data-lights="lights-off"] .lamp-glow {
  opacity: .25;
  transition: opacity .25s linear;
}

当有人打开灯时,它会在看似随机的时间间隔闪烁。我首先为闪烁元素应用了一个类值:

1
<path class="lamp-flicker" />

然后在灯关闭时隐藏它们:

1
2
3
[data-lights="lights-off"] .lamp-flicker {
  visibility: hidden;
}

最后,我创建了一个关键帧动画,在看似随机的时间间隔闪烁灯光的透明度:

1
2
3
4
5
6
7
8
@keyframes lamp-flicker {
  0%, 19.9%, 22%, 62.9%, 64%, 64.9%, 70%, 100% { opacity: 1; }
  20%, 21.9%, 63%, 63.9%, 65%, 69.9% { opacity: .5; }
}

[data-lights="lights-on"] .lamp-flicker {
  animation: lamp-flicker 3s 3s linear infinite;
}

动画还可以吸引人们深入探索设计,因此我让桌子上的水晶头骨振动,以暗示有更多内容可以发现:

1
2
3
<a href="/easter-egg">
  <g id="crystal-skull">...</g>
</a>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@keyframes crystal-skull-vibrate {
  0% { translate: 0 0; }
  20% { translate: -2px 2px; }
  40% { translate: -2px -2px; }
  60% { translate: 2px 2px; }
  80% { translate: 2px -2px; }
  100% { translate: 0 0; }
}

#crystal-skull:hover {
  animation: crystal-skull-vibrate .5s ease 0s infinite normal forwards;
}

动画讲述故事

经过仔细考虑,动画可以反映品牌的 identity 并帮助讲述其故事。

Mike Worth的品牌是高能量的——就像他的个性一样——他关于自己作为视频游戏作曲家的工作的故事引人入胜且有趣。Mike希望与他的网站的每一次互动都能将他的个性带到屏幕上。

如果有人迷路了,他们会最终进入Mike的404页面,在那里他的英雄有一种下沉的感觉。当Mike的猩猩冒险者越来越深地陷入流沙时,动画气泡上升:

1
2
3
4
5
6
<g>
  <circle class="four-oh-dear-bubble" ... />
  <circle class="four-oh-dear-bubble" ... />
  <circle class="four-oh-dear-bubble" ... />
  <!-- ... -->
</g>
 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
35
36
37
38
@keyframes four-oh-dear-bubbles {
  0% { 
    animation-timing-function: ease-in; 
    opacity: 1; 
    transform: translateY(45px);
  }
  24% { 
    opacity: 1; 
  }
  40% { 
    animation-timing-function: ease-in; 
    translate: 0 24px;
  }
  65% { 
    animation-timing-function: ease-in;
    translate: 0 12px;
  }
  82% { 
    animation-timing-function: ease-in;
    translate: 0 6px;
  }
  93% { 
    animation-timing-function: ease-in;
    translate: 0 4px;
  }
  25%, 55%, 75%, 87% { 
    animation-timing-function: ease-out;
    translate: 0 0;
  }
  100% { 
    animation-timing-function: ease-out;
    opacity: 1; 
    translate: 0 0;
  }
}

.four-oh-dear-bubble {
  animation: four-oh-dear-bubbles 2s ease 0s infinite alternate forwards; }

将所有内容带入生活

就像汉纳-巴伯拉的动画师将技术限制转化为他们的标志性风格一样,CSS动画使网页专业人士能够制作有个性的体验。通过分层元素、循环帧和应用微妙的运动,您可以为设计注入个性,同时改善某人的体验。

在我为Mike Worth网站的设计中,动画不仅仅是为了装饰;它讲述了一个关于他和他工作的引人入胜的故事。每一个动作都反映了他的品牌 identity,并使他的网站成为他创意世界的延伸。

下次您使用CSS动画时,请超越运动思考。也要考虑情感、 identity 和 mood。毕竟,一个经过深思熟虑的动画可以做的不仅仅是吸引某人的眼球。它可以捕捉他们的想象力。

Mike Worth的网站将于2025年6月推出,但您现在可以在CodePen上看到本文中的示例。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计