我如何为我的纸牌游戏选择动画库

Avatar of Holger Sindbaek
Holger Sindbaek

DigitalOcean 为您旅程的每个阶段提供云产品。从 价值 200 美元的免费积分! 开始吧。

市面上有大量的 CSS 和 JavaScript 动画库。事实上,它们太多了,以至于选择适合您项目的动画库似乎是不可能的。当我决定开发一个 在线纸牌游戏 时,我遇到了这种情况。我知道我需要一个动画库,但我应该选择哪一个呢?

在本文中,我将介绍我做了哪些考虑,需要留意什么,并向您展示一些最流行的可用库。我将与您一起了解一些现实世界的例子来说明我的观点,最后,希望当您第一次必须选择动画库时,您比我准备得更充分。

当然,您对这些建议的使用效果可能会有所不同。我在这里分享的所有内容都是针对我想要构建的特定内容。您的项目可能具有完全不同的需求和优先级,这没关系。我认为重要的是,在这里了解到一个 像前端开发人员一样思考 并具有特定目标的亲身经历。

说到这一点,我确实认为自己是一名前端开发人员,但我的背景非常偏重于设计。所以我知道代码,但没有达到 JavaScript 工程师的水平。我只想澄清一下,因为经验肯定会影响最终决定。

目标

在我们开始任何决策之前,让我们看一下我在这个 CSS-Tricks 风格的游戏中需要进行的动画类型

很酷,对吧?这些动画并没有什么特别简单的地方。有很多事情发生——有时是同时发生的——并且有很多东西需要编排。此外,大多数动画都是由用户交互触发的。因此,这让我在进入我的决定时有了几个优先事项

  • 流畅的动画:动画的应用方式会对它们是否流畅运行或显示一些卡顿产生很大影响。
  • 性能:采用任何库都会为项目增加负担,我希望我的游戏尽可能精简。
  • 便利性:我希望有一个漂亮、简洁的语法,使编写和管理动画变得更容易。如果它允许我编写更好、更易于维护的代码,我甚至愿意用一点额外的便利性来换取少许性能损失。同样,这对设计师转型为开发人员来说是个好兆头。
  • 浏览器支持:当然,我希望我的游戏能够在任何现代浏览器上运行,并使用某种形式的渐进式增强来防止完全破坏传统浏览器。此外,我绝对希望有一些面向未来的功能。

这就是我在寻找适合此特定工作的工具时所带的东西。

选择 CSS 或 JavaScript 动画库

在选择动画库时,我首先考虑的是是使用基于 CSS 的库还是基于 JavaScript 的库。有许多 很棒的 CSS 库,其中许多库具有出色的性能,这对我来说是一个优先事项。我想要进行一些高强度的动画,比如能够对动画进行排序并在动画完成时获得回调。用纯 CSS 完全可以实现这一切——但它不像大多数 JavaScript 库提供的那样流畅。

让我们看看在 CSS 中简单的排序动画是如何实现的,并将其与 jQuery 进行比较,jQuery 具有许多内置的动画辅助工具

动画看起来一样,但创建方式不同。要制作 CSS 动画,首先,我们必须在 CSS 中定义关键帧动画,并将其附加到一个类

.card.move {
  animation : move 2s;
}

@keyframes move {
  0% { left: 0 }
  50% { left: 100px }
  100% { left: 0 }
}

然后,我们使用 JavaScript 执行动画并侦听元素上的 CSS 回调

var cardElement = document.getElementsByClassName("card")[0];
var statusElement = document.getElementsByClassName("status")[0];

cardElement.classList.add("move");
statusElement.innerHTML = "Animating"

var animationEndCallback = function() {
  cardElement.classList.remove("move");
  statusElement.innerHTML = "Inactive"
}

cardElement.addEventListener("webkitAnimationEnd", animationEndCallback);
cardElement.addEventListener("oAnimationEnd", animationEndCallback); 
cardElement.addEventListener("antionend", animationEndCallback);

在像这样的简单示例中,将事物放在不同的地方可能没问题,但是一旦事情变得更加复杂,它就会变得非常混乱。

将它与 jQuery 如何完成动画进行比较

$(".status").text("Animating")
$( ".card" ).animate({
  left: "100px"
}, 1000);
$( ".card" ).animate({
  left: 0
}, 1000, function() {
  $(".status").text("Inactive")
});

在这里,所有内容都发生在同一个地方,如果动画将来变得更加复杂,可以简化操作。

很明显,使用 JavaScript 库是正确的选择,但对于我的纸牌游戏来说,哪一个是正确的选择呢?我的意思是,jQuery 很棒,并且 即使在今天仍然被广泛使用,但这并不是我想依赖的东西。有许多 JavaScript 动画库,因此我想考虑一些专门为处理我想要的这种复杂动画而构建的库。

选择 JavaScript 动画库

我很快发现,JavaScript 动画库并不缺乏,并且有 新的、令人兴奋的技术。它们都有优点和缺点,所以让我们来看看我考虑过的一些库以及原因。

Web 动画 API 就是这样一个例子,它可能在将来取代许多 JavaScript 动画库。有了它,您将能够创建复杂的交错动画,而无需加载任何外部库,并且具有与 CSS 动画相同的性能。唯一的缺点是 并非所有浏览器都支持它

<canvas> 元素提供另一个令人兴奋的机会。在其中,我们可以使用 JavaScript 对事物进行动画处理,就像我们对 DOM 所做的那样,但动画被渲染为光栅,这意味着我们可以制作一些高性能动画。唯一的缺点是 canvas 元素本质上是在 DOM 中被渲染为图像,因此,如果我们想要像素级完美,我们可能就没办法了。作为一名对设计非常敏感的人,这对我来说是一个无法接受的条件。

我需要一些经过验证和测试的东西,所以我知道我可能不得不选择众多 JavaScript 库中的一个。我开始研究一些库,并将我的选择范围缩小到 Anime.jsGSAP。它们似乎都能很好地处理复杂的动画,并且在性能方面有很好的记录。Anime 是一个维护良好的库,在 GitHub 上拥有超过 42,000 颗星,而 GSAP 是一个超级流行、经过实战检验的库,拥有一个繁荣的社区。

一个活跃的社区对我来说至关重要,因为我需要一个可以寻求帮助的地方,而且我不想使用可能后来被放弃的库。我将此作为我便利性需求的一部分进行考虑。

对动画进行排序和回调

一旦我将选择范围缩小,下一步就是使用我的两个库实现一个复杂的动画。纸牌游戏中经常出现一种动画,即一张牌移动到某个地方,然后翻过来,让我们看看它是什么样子

这两个动画看起来都很棒!它们很流畅,实现它们都很简单。两个库都有一个 时间轴函数,可以轻松创建序列。这就是在 AnimeJS 中实现的方式

var timeline = anime.timeline({
  begin: function() {
    $(".status").text("Animating")
  },
  complete: function() {
    $(".status").text("Inactive")
  }
});

timeline.add({
  targets: '.card',
  left: [0, 300],
  easing: 'easeInOutSine',
  duration: 500
}).add({
  targets: '.card .back',
  rotateY: [0, 90],
  easing: 'easeInSine',
  duration: 200
}).add({
  targets: '.card .front',
  rotateY: [-90, 0],
  easing: 'easeOutSine',
  duration: 200
})

Anime 的 timeline() 函数 内置了动画开始和结束时的回调,创建序列就像附加顺序动画一样简单。首先,我移动卡片,然后将背面图像旋转 90 度,使其消失,然后将正面图像旋转 90 度,使其出现。

使用 GSAP 的 timeline() 函数 完成相同实现的方式非常相似

var timeline = gsap.timeline({
  onStart: function() {
    $(".status").text("Animating")
  },
  onComplete: function() {
    $(".status").text("Inactive")
  }
});

timeline.fromTo(".card", {
  left: 0
}, {
  duration: 0.5,
  left: 300
}).fromTo(".card .back", {
  rotationY: 0
}, {
  rotationY: 90,
  ease: "power1.easeIn",
  duration: 0.2
}).fromTo(".card .front", {
  rotationY: -90
}, {
  rotationY: 0,
  ease: "power1.easeOut",
  duration: 0.2
})

做出决定

Anime 和 GSAP 之间的主要区别似乎在于语法,GSAP 可能更详细一些。我被两个很棒的库困住了,它们具有非常相似的功能,能够处理复杂的动画,并且拥有一个繁荣的社区。看来我遇到了平局!

优先级AnimeGSAP
流畅的动画
性能
便利性
浏览器支持

那么,是什么让我选择了其中一个库而不是另一个呢?

我非常担心库在压力下会如何表现。在像纸牌这样的游戏中,动画滞后会极大地影响游戏的趣味性。我知道在创建游戏之前,我无法完全了解库的性能。幸运的是,GSAP 已经做了一个 压力测试,将不同的动画库进行比较,包括 Anime。

看到这一点,GSAP 显然是处理大量复杂动画的最佳库。GSAP 在一个复杂的动画中能达到每秒 26 帧的帧率,而 Anime 只能达到 19 帧。在进一步了解 GSAP 并查看其论坛后,很明显,性能是 GSAP 团队的首要任务。

尽管 GSAP 和 Anime 都已经存在一段时间了,但 Anime 的代码库在过去几年里一直处于休眠状态,而 GSAP 在过去几个月里一直在更新代码。

我最终使用了 GSAP,并且没有后悔我的决定!

你呢?这是否符合你评估和比较前端工具的方式?在类似的项目中,你是否考虑过其他优先事项(例如可访问性等)?或者你是否在某个项目中不得不从多个选项中缩减选择范围?请在评论区分享你的想法,因为我非常想知道!

哦,如果你想看看用动画制作一副牌的样子,你可以访问我的网站并玩一局纸牌游戏。玩得开心!