将第三方动画库集成到项目中

Avatar of Travis Almand
Travis Almand

DigitalOcean 提供适合您旅程各个阶段的云产品。立即开始使用 $200 免费积分!

创建基于 CSS 的动画和过渡可能是一项挑战。它们可能很复杂且耗时。需要在项目中快速前进,但没有时间调整完美的过渡?考虑使用第三方 CSS 动画库,它提供随时可用的动画,等待您使用。但是,您可能在想:它们是什么?它们提供了什么?我该怎样使用它们?

让我们来找出答案。

关于 :hover 的简短历史

曾经有一段时间,悬停状态的概念是今天提供功能的简单示例。事实上,鼠标指针悬停在元素上时产生反应的想法几乎不存在。人们提出了并实施了不同的方式来提供此功能。从某种程度上来说,这一小小的功能为 CSS 能够为页面上的元素进行动画的想法打开了大门。随着时间的推移,这些功能的日益复杂性导致了 CSS 动画库的诞生。

Macromedia 的 Dreamweaver1997 年 12 月 推出,它提供了一个简单的功能,即悬停时图像交换。此功能是通过 JavaScript 函数实现的,该函数将由编辑器嵌入到 HTML 中。此函数名为 MM_swapImage(),已成为网页设计传奇的一部分。它是一个易于使用的脚本,即使在 Dreamweaver 之外也是如此,其受欢迎程度导致它至今仍在使用。在我为本文进行的初步研究中,我发现一个关于此函数的问题,它来自 2018 年 Adobe 的 Dreamweaver(Adobe 于 2005 年收购了 Macromedia)帮助论坛。

JavaScript 函数将通过更改基于 mouseovermouseout 事件的 src 属性,将一个图像替换为另一个图像。当实施时,它看起来像这样

<a href="#" onMouseOut="MM_swapImgRestore()" onMouseOver="MM_swapImage('ImageName','','newImage.jpg',1)">
  <img src="originalImage.jpg" name="ImageName" width="100" height="100" border="0">
</a>

按照今天的标准,用 JavaScript 实现这一目标相当容易,我们中的许多人几乎可以在睡梦中做到。但请记住,JavaScript 当时还是一种新的脚本语言(创建于 1995 年),有时在不同浏览器中的外观和行为也不同。创建跨浏览器 JavaScript 并不总是容易的事,并不是所有创建网页的人都会编写 JavaScript。(尽管情况肯定发生了变化。)Dreamweaver 通过编辑器中的菜单提供此功能,网页设计师甚至不需要编写 JavaScript 代码。它是基于一组“行为”,这些行为可以从不同的选项列表中进行选择。这些选项可以通过一组目标浏览器进行筛选;3.0 浏览器、4.0 浏览器、IE 3.0、IE 4.0、Netscape 3.0、Netscape 4.0。啊,美好的旧时光

A screenshot of a Netscape browser window.
根据浏览器版本选择行为,大约在 1997 年。
A screenshot from the Dreamweaver application that shows the options panel for toggling an element's behavior in HTML.
Macromedia Dreamweaver 1.2a 中的交换图像行为面板

在 Dreamweaver 首次发布大约一年后,W3C 的 CSS2 规范在 1998 年 1 月 的工作草案中提到了 :hover。它是在锚链接方面特别提到的,但语言暗示它可能应用于其他元素。对于大多数目的,此伪选择器似乎将成为 MM_swapImage() 的简单替代方案的开始,因为 background-image 位于同一草案中。尽管浏览器支持是一个问题,因为花了数年时间,直到足够多的浏览器正确支持 CSS2,才使其成为许多网页设计师的可行选择。最终,CSS2.1 获得了 W3C 推荐,这可以被认为是我们所知的“现代”CSS 的基础,该规范于 2011 年 6 月 发布。

在这一切的中间,jQuery2006 年 出现。值得庆幸的是,jQuery 在简化不同浏览器之间的 JavaScript 方面走得更远。对我们故事有趣的一件事是,jQuery 的第一个版本提供了 animate() 方法。使用此方法,您可以随时对任何元素上的 CSS 属性进行动画处理;不仅仅是悬停时。凭借其巨大的流行度,此方法暴露了对烘焙在浏览器中的更强大 CSS 解决方案的需求——一种不需要 JavaScript 库的解决方案,由于浏览器限制,该库并不总是很有效。

:hover 伪类只提供了一种从一个状态到另一个状态的硬切换,不支持平滑过渡。它也不能对除悬停在元素上之外的元素进行动画更改。jQuery 的 animate() 方法提供了这些功能。它为我们铺平了道路,而且没有回头路。正如网页开发动态世界中发生的事情一样,在发布 CSS2.1 推荐之前,已经有一个工作草案用于解决这个问题。 CSS 过渡模块级别 3 的第一个工作草案于 2009 年 3 月由 W3C 首次发布。 CSS 动画模块级别 3 的第一个工作草案大约在同一时间发布。截至 2018 年 10 月,这两个 CSS 模块仍处于工作草案状态,但当然,我们已经开始大量使用它们。

因此,最初是由第三方提供的用于简单悬停状态的 JavaScript 函数,已经发展成为 CSS 中的过渡和动画,允许进行复杂且精美的动画——许多开发人员并不希望考虑这些复杂性,因为他们需要在新的项目上快速行动。我们已经走了一个完整的圆圈;如今,许多第三方 CSS 动画库的创建是为了抵消这种复杂性。

三种不同类型的第三方动画库

我们正处于这个新世界中,能够在我们的网页和应用程序中实现强大、令人兴奋且复杂的动画。关于如何处理这些新任务,出现了几个不同的想法。并不是说一种方法比另一种方法更好;事实上,它们之间有很多重叠。区别在于我们如何实现和编写代码。有些是完整的纯 JavaScript 库,而另一些则是纯 CSS 集合。

JavaScript 库

完全通过 JavaScript 操作的库通常提供超出普通 CSS 动画的功能。通常情况下,会有一些重叠,因为库实际上可能会使用 CSS 功能作为其引擎的一部分,但这些功能将被抽象掉以有利于 API。此类库的示例包括 GreensockAnime.js。您可以通过查看它们提供的演示来了解它们提供的功能范围(Greensock 在 CodePen 上有一个 不错的集合)。它们主要用于高度复杂的动画,但对于更基本的动画也很有用。

JavaScript 和 CSS 库

有一些第三方库主要包含 CSS 类,但提供一些 JavaScript 以便在您的项目中轻松使用这些类。一个库,Micron.js,提供 JavaScript API 和可以在元素上使用的数据属性。这种类型的库允许轻松使用您可以从中选择的预构建动画。另一个库,Motion UI,旨在与 JavaScript 框架一起使用。虽然它也基于类似的概念,即 JavaScript API、预构建类和数据属性的混合。这些类型的库提供了预构建动画和一种简便的方式来连接它们。

CSS 库

第三种库是纯 CSS 库。通常,这只是一个 CSS 文件,你通过 HTML 中的链接标签加载它。然后,你可以应用和删除特定的 CSS 类来使用提供的动画。这种类型的库的两个例子是 Animate.cssAnimista。也就是说,这两个库之间仍然存在着很大的区别。Animate.css 是一个完整的 CSS 包,而 Animista 提供了一个简洁的界面,让你可以选择你想要的动画并提供代码。这些库通常很容易实现,但是你需要编写代码来使用它们。本文将重点介绍这种类型的库。

三种不同的 CSS 动画类型

是的,存在一个模式;毕竟,三一律无处不在。

在大多数情况下,在使用第三方库时,需要考虑三种类型的动画。每种类型都适合不同的用途,并且有不同的使用方法。

悬停动画

An illustration of a black button on the left and an orange button with a mouse cursor over it as a hover effect.

这些动画旨在参与某种悬停状态。它们通常与按钮一起使用,但另一种可能性是使用它们来突出显示光标碰巧位于的区域。它们也可以用于焦点状态。

注意力动画

An illustration of a webpage with gray boxes and a red alert at the top of the screen to show an instance of an element that seeks attention.

这些动画旨在用于通常位于观看页面的人的视觉中心之外的元素。将动画应用于需要引起注意的显示区域。此类动画对于需要最终注意但性质不紧急的事物来说可能是微妙的。对于需要立即注意的事物,它们也可能极具干扰性。

过渡动画

An illustration of concentric circles stacked vertically going from gray to black in ascending order.

这些动画通常旨在让一个元素替换视图中的另一个元素,但也可以用于单个元素。这些通常包括一个“离开”视图的动画和一个“进入”视图的镜像动画。想想淡出和淡入。这在单页应用程序中很常见,因为例如,一个数据部分将过渡到另一组数据。

因此,让我们回顾一下每种动画类型的示例以及如何使用它们。

让我们来悬停一下!

某些库可能已经为悬停效果设置好了,而有些库则以悬停状态为主要用途。其中一个这样的库是 Hover.css,它是一个即插即用解决方案,提供了一系列通过类名应用的悬停效果。但是,有时我们希望在一个库中使用动画,而该库并不直接支持 :hover 伪类,因为这可能会与全局样式发生冲突。

对于此示例,我将使用 Animate.css 提供的 tada 动画。它更适合用作注意力吸引器,但对于此示例来说已经足够好了。如果你要 查看库的 CSS,你会发现没有找到 :hover 伪类。因此,我们必须自己以这种方式使它起作用。

tada 类本身就是这个

.tada {
  animation-name: tada;
}

使此动画对悬停状态做出反应的低成本方法是制作我们自己的本地类副本,但稍微扩展一下。通常,Animate.css 是一个即插即用解决方案,因此我们不一定可以选择编辑原始 CSS 文件;尽管你也可以拥有自己的本地文件副本,如果你愿意的话。因此,我们只创建我们需要更改的代码,并让库处理其余部分。

.tada-hover:hover {
  animation-name: tada;
}

我们可能不应该覆盖原始类名,以防我们实际上想在其他地方使用它。因此,我们制作了一个变体,我们可以将 :hover 伪类放在选择器上。现在,我们只需将库所需的 animated 类和我们的自定义 tada-hover 类应用于元素,它就会在悬停时播放该动画。

如果你不想以这种方式创建自定义类,而是更喜欢 JavaScript 解决方案,则有一种相对简单的方法可以处理它。说来奇怪,这与我们之前讨论过的 Dreamweaver 中的 MM_imageSwap() 方法类似。

// Let's select elements with ID #js_example
var js_example = document.querySelector('#js_example');

// When elements with ID #js_example are hovered...
js_example.addEventListener('mouseover', function () {
  // ...let's add two classes to the element: animated and tada...
  this.classList.add('animated', 'tada');
});
// ...then remove those classes when the mouse is not on the element.
js_example.addEventListener('mouseout', function () {
  this.classList.remove('animated', 'tada');
});

实际上有几种方法可以处理这个问题,具体取决于上下文。在这里,我们创建了一些事件监听器来等待鼠标悬停和鼠标移出事件。这些监听器会根据需要应用和删除库的 animatedtada 类。正如你所见,稍微扩展一个第三方库以适应我们的需求,可以以相对简单的方式完成。

请注意我一下?

第三方库可以帮助实现的另一种动画类型是注意力吸引器。这些动画在你想将注意力吸引到页面上的某个元素或区域时非常有用。这方面的一些例子包括通知或未填写的必填表单输入。这些动画可以是微妙的或直接的。对于最终需要关注但不需要立即解决的问题,可以使用微妙的动画。对于需要立即解决的问题,可以使用直接的动画。

某些库将此类动画作为整个包的一部分,而有些库则是专门为此目的而构建的。Animate.css 和 Animista 都有注意力吸引动画,但它们不是这些库的主要用途。一个专门为此目的而构建的库示例是 CSShake。使用哪个库取决于项目的需要以及你希望投入多少时间来实现它们。例如,CSShake 几乎不需要任何麻烦就能使用,只需根据需要应用类即可。但是,如果你已经在使用 Animate.css 等库,那么你可能不想引入第二个库(为了性能、依赖关系等)。

因此,可以使用 Animate.css 之类的库,但需要进行更多设置。该库的 GitHub 页面上有一些示例,说明如何执行此操作。取决于项目的需要,将这些动画实现为注意力吸引器相当简单。

对于一种微妙的动画类型,我们可以使用一种只重复一定次数并停止的动画。这通常涉及添加库的类,将动画迭代属性应用于 CSS,以及等待动画结束事件来清除库的类。

这是一个简单的示例,它遵循我们之前为悬停状态所看到的相同模式

var pulse = document.querySelector('#pulse');

function playPulse () {
  pulse.classList.add('animated', 'pulse');
}

pulse.addEventListener('animationend', function () {
  pulse.classList.remove('animated', 'pulse');
});

playPulse();

在调用 playPulse 函数时应用库类。有一个用于 animationend 事件的事件监听器,它将删除库的类。通常,这只会播放一次,但你可能希望在停止之前重复多次。Animate.css 没有为此提供类,但为我们的元素应用 CSS 属性来处理此问题非常容易。

#pulse {
  animation-iteration-count: 3; /* Stop after three times */
}

这样,动画将在停止之前播放三次。如果我们需要更早地停止动画,则可以在 animationend 函数之外手动删除库类。该库的文档实际上提供了一个可重用函数的示例,用于应用在动画结束后删除类的函数;与上面的代码非常相似。甚至可以很容易地扩展它,将迭代计数应用于元素。

对于更直接的方法,假设有一个无限动画,它不会停止,直到发生某种用户交互。假设点击该元素是启动动画,再次点击是停止动画。请记住,你希望如何启动和停止动画取决于你自己。

var bounce = document.querySelector('#bounce');

bounce.addEventListener('click', function () {
  if (!bounce.classList.contains('animated')) {
    bounce.classList.add('animated', 'bounce', 'infinite');
  } else {
    bounce.classList.remove('animated', 'bounce', 'infinite');
  }
});

很简单。点击元素会测试库的“animated”类是否已应用。如果没有,我们应用库类,使其启动动画。如果它具有这些类,我们将其删除以停止动画。请注意 classList 末尾的 infinite 类。值得庆幸的是,Animate.css 为我们提供了开箱即用的功能。如果你的库没有提供此类类,则需要在 CSS 中使用以下代码

#bounce {
  animation-iteration-count: infinite;
}

这是一个演示,展示了此代码的行为

查看 CodePen 上的
第三方动画库:注意力吸引器
,作者是 Travis Almand (@talmand)
CodePen 上。

把东西移开

在研究这篇文章时,我发现过渡(不要与 CSS 过渡混淆)是第三方库中最常见的动画类型。这些是简单的动画,旨在允许元素进入或离开页面。现代单页面应用程序中常见的模式是让一个元素离开页面,而另一个元素进入页面以替换它。想象一下第一个元素淡出而第二个元素淡入。这可以是使用新数据替换旧数据、移动到序列中的下一个面板或使用路由器从一个页面移动到另一个页面。Sarah DrasnerGeorgy Marchuk 都提供了这些类型过渡的优秀示例。

在大多数情况下,动画库不会提供在过渡动画期间移除和添加元素的方法。提供额外 JavaScript 的库实际上可能具有此功能,但由于大多数库不提供,我们将讨论如何现在处理此功能。

插入单个元素

对于此示例,我们将再次使用 Animate.css 作为我们的库。在这种情况下,我将使用 fadeInDown 动画。

现在,请记住,有很多方法可以处理将元素插入 DOM,我不想在这里介绍它们。我只想展示如何利用动画使插入更漂亮、更自然,而不是元素简单地弹出到视图中。对于 Animate.css(以及可能许多其他库),使用动画插入元素非常容易。

let insertElement = document.createElement('div');
insertElement.innerText = 'this div is inserted';
insertElement.classList.add('animated', 'fadeInDown');

insertElement.addEventListener('animationend', function () {
  this.classList.remove('animated', 'fadeInDown');
});

document.body.append(insertElement);

无论您如何决定创建元素,都不重要;您只需要确保在插入元素之前已应用必要的类。然后它会很好地动画到适当的位置。我还包含了 animationend 事件的事件监听器,它会移除类。像往常一样,有几种方法可以做到这一点,这可能是处理它的最直接方法。移除类的目的是为了更容易在需要时反转该过程。我们不希望进入动画与离开动画竞争。

移除单个元素

移除单个元素有点类似于插入元素。元素已经存在,因此我们只需应用所需的动画类。然后在 animationend 事件中,我们将元素从 DOM 中移除。在此示例中,我们将使用 Animate.css 中的 fadeOutDown 动画,因为它与 fadeInDown 动画配合得很好。

let removeElement = document.querySelector('#removeElement');

removeElement.addEventListener('animationend', function () {
  this.remove();
});

removeElement.classList.add('animated', 'fadeOutDown');

如您所见,我们定位元素、添加类并在动画结束时移除元素。

所有这些的一个问题是,以这种方式插入和移除元素会导致页面上的其他元素跳动以进行调整。您必须以某种方式解决这个问题,最有可能的是使用 CSS 和页面的布局来为元素保留一个恒定空间。

让开,我要来了!

现在我们将交换两个元素,一个离开,另一个进入。有多种方法可以处理这种情况,但我将提供一个示例,它基本上将前面的两个示例结合在一起。

查看笔:
第三方动画库:过渡两个元素
by Travis Almand (@talmand)
CodePen 上。

我将分部分介绍 JavaScript 来解释它是如何工作的。首先,我们缓存对按钮和两个元素容器的引用。然后,我们创建两个将在容器内交换的盒子。

let button = document.querySelector('button');
let container = document.querySelector('.container');
let box1 = document.createElement('div');
let box2 = document.createElement('div');

我有一个通用函数,用于为每个 animationEnd 事件移除动画类。

let removeClasses = function () {
  box1.classList.remove('animated', 'fadeOutRight', 'fadeInLeft');
  box2.classList.remove('animated', 'fadeOutRight', 'fadeInLeft');
}

下一个函数是交换功能的核心。首先,我们确定当前显示的盒子。基于此,我们可以推断出离开和进入的元素。离开的元素首先移除调用 switchElements 函数的事件监听器,这样我们就不会陷入动画循环。然后,我们移除离开的元素,因为它动画已经完成。接下来,我们向进入的元素添加动画类,并将其附加到容器中,这样它就会动画到适当的位置。

let switchElements = function () {
  let currentElement = document.querySelector('.container .box');
  let leaveElement = currentElement.classList.contains('box1') ? box1 : box2;
  let enterElement = leaveElement === box1 ? box2 : box1;
  
  leaveElement.removeEventListener('animationend', switchElements);
  leaveElement.remove();
  enterElement.classList.add('animated', 'fadeInLeft');
  container.append(enterElement);
}

我们需要对两个盒子进行一些常规设置。此外,我们将第一个盒子附加到容器中。

box1.classList.add('box', 'box1');
box1.addEventListener('animationend', removeClasses);
box2.classList.add('box', 'box2');
box2.addEventListener('animationend', removeClasses);

container.appendChild(box1);

最后,我们有一个按钮的点击事件监听器,它会进行切换。这些事件序列是如何启动的,这在技术上取决于您。对于此示例,我决定使用简单的按钮点击。我弄清楚当前显示的是哪个盒子,它将要离开,以便应用适当的类使其动画退出。然后我为 animationEnd 事件应用一个事件监听器,它调用上面显示的 switchElements 函数,该函数处理实际的交换。

button.addEventListener('click', function () {
  let currentElement = document.querySelector('.container .box');
  
  if (currentElement.classList.contains('box1')) {
    box1.classList.add('animated', 'fadeOutRight');
    box1.addEventListener('animationend', switchElements);
  } else {
    box2.classList.add('animated', 'fadeOutRight');
    box2.addEventListener('animationend', switchElements);
  }
}

此示例的一个明显问题是,它对这种情况非常硬编码。不过,它可以轻松扩展和调整以适应不同的情况。因此,这个例子在理解处理这种任务的一种方法方面很有用。值得庆幸的是,一些动画库,例如 MotionUI,提供了一些 JavaScript 来帮助进行元素过渡。另一个要考虑的是,一些 JavaScript 框架,例如 VueJS,具有帮助动画化元素过渡的功能。

我还创建了另一个示例,它提供了一个更灵活的系统。它包含一个容器,该容器使用数据属性存储对离开和进入动画的引用。该容器包含两个元素,这些元素将在命令下交换位置。构建此示例的方式是,可以通过 JavaScript 很容易地更改数据属性中的动画。我在演示中还有两个容器;一个使用 Animate.css,另一个使用 Animista 进行动画。这是一个很大的示例,因此我不会在这里检查代码;但它有大量的注释,所以如果有兴趣可以看看。

查看笔:
第三方动画库:自定义过渡示例
by Travis Almand (@talmand)
CodePen 上。

花点时间考虑一下……

每个人都真的想看到所有这些动画吗?有些人可能会认为我们的动画过分且不必要,但对于有些人来说,它们实际上会造成问题。前段时间,WebKit 引入了 prefers-reduced-motion 媒体查询,以帮助解决可能的 前庭系统疾病 问题。Eric Bailey 还 发布了关于媒体查询的不错介绍,以及 关于最佳实践考虑因素的后续文章。一定要阅读这些文章。

那么,您选择的动画库是否支持 prefers-reduced-motion?如果文档中没有说明它支持,那么您可能要假设它不支持。不过,检查库的代码以查看是否有任何媒体查询内容相当容易。例如,Animate.css 在 _base.scss 部分文件中提供了此功能。

@media (print), (prefers-reduced-motion) {
  .animated {
    animation: unset !important;
    transition: none !important;
  }
}

这段代码还提供了一个很好的示例,说明如果库不支持,如何自己实现。如果库使用一个通用类(例如 Animate.css 使用“animated”),那么您只需定位该类。如果它不支持这样的类,那么您必须定位实际的动画类或为该目的创建自己的自定义类。

.scale-up-center {
  animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
}

@keyframes scale-up-center {
  0% { transform: scale(0.5); }
  100% { transform: scale(1); }
}

@media (print), (prefers-reduced-motion) {
  .scale-up-center {
    animation: unset !important;
    transition: none !important;
  }
}

如您所见,我使用了 Animate.css 提供的示例,并定位了来自 Animista 的动画类。请记住,您必须对从库中选择的每个动画类重复此操作。不过,在 Eric 的后续文章中,他建议将所有动画视为渐进增强,这可能是减少代码并创造更易于访问的用户体验的一种方式。

让框架为您完成繁重的工作

在很多方面,React 和 Vue 等各种框架都可以使使用第三方 CSS 动画比使用原生 JavaScript 更容易,主要是因为您不必手动连接类交换或 animationend 事件。您可以利用框架已经提供的功能。使用框架的美妙之处在于,它们还提供了几种不同的方法来处理这些动画,具体取决于项目的需要。以下示例只是选项的一个小示例。

悬停效果

对于悬停效果,我建议使用 CSS(正如我上面建议的那样)作为更好的方法。如果您在框架中确实需要一个 JavaScript 解决方案,例如 Vue,那么它将类似于以下内容

<button @mouseover="over($event, 'tada')" @mouseleave="leave($event, 'tada')">
  tada
</button>
methods: {
  over: function(e, type) {
    e.target.classList.add('animated', type);
  },
  leave: function (e, type) {
    e.target.classList.remove('animated', type);
  }
}

与上面的原生 JavaScript 解决方案没有太大区别。此外,与以前一样,有很多方法可以处理这种情况。

吸引注意力

设置吸引注意力元素实际上更容易。在这种情况下,我们只需应用所需的类,同样,以 Vue 为例。

<div :class="{animated: isPulse, pulse: isPulse}">pulse</div>

<div :class="[{animated: isBounce, bounce: isBounce}, 'infinite']">bounce</div>

在脉冲示例中,每当布尔值 isPulse 为真时,就会应用这两个类。在弹跳示例中,每当布尔值 isBounce 为真时,就会应用 animatedbounce 类。infinite 类始终被应用,因此我们可以一直持续弹跳,直到 isBounce 布尔值变为假。

过渡

幸运的是,Vue 的 过渡组件 提供了一种简单的方法,可以使用第三方动画类与 自定义过渡类。其他库,如 React,可以提供 类似功能或附加组件。为了利用 Vue 中的动画类,我们只需在过渡组件中实现它们。

<transition
  enter-active-class="animated fadeInDown"
  leave-active-class="animated fadeOutDown"
  mode="out-in"
>
  <div v-if="toggle" key="if">if example</div>
  <div v-else key="else">else example</div>
</transition>

使用 Animate.css,我们只需应用必要的类。对于 enter-active,我们应用了所需的 animated 类以及 fadeInDown。对于 leave-active,我们应用了所需的 animated 类以及 fadeOutDown。在过渡序列期间,这些类将在适当的时间插入。Vue 为我们处理类的插入和移除。

有关在 JavaScript 框架中使用第三方动画库的更复杂示例,请查看此项目

查看 Pen
KLKdJy
by Travis Almand (@talmand)
CodePen 上。

加入派对!

这只是您项目中可能出现的众多第三方 CSS 动画库中的一小部分。有些库 非常全面古怪专一令人讨厌,或者仅仅 简单易用。还有一些库用于复杂的 JavaScript 动画,如 GreensockAnime.js。甚至还有针对 元素字符 的库。

希望所有这些都能激发您在创建自己的 CSS 动画的路上尝试这些库。