抛弃 .gif:目前性能最佳的图像和视频选项

Avatar of Ollie Williams
Ollie Williams

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

所以您想要一个自动播放循环的无声视频?在流行的口语中,这就是“GIF”一词的真正含义。这个词一直沿用至今,但图像格式本身已经过时且陈旧。例如,Twitter 有一个“GIF”按钮,实际上会在您的推文中插入一个包含 MP4 文件的 <video> 元素——没有 .gif 的影子。实现相同结果的方法有很多,但有一点很明确:现在真的没有理由再使用笨重的 .gif 文件格式了。

使用 HTML <video> 元素

使用 HTML 视频元素可以轻松地再现 GIF 的行为。

<video autoplay loop muted playsinline src="cats.mp4"></video>

使用此代码,视频将自动以连续循环的方式播放,并且没有音频。 playsinline 表示移动浏览器将在页面上的视频所在位置播放视频,而不是以全屏方式打开。

虽然 HTML 视频元素本身已经支持多年,但不能说各种视频格式也一样。

视频由两部分组成:容器和视频编解码器。(如果您的视频包含音频,则由三部分组成,第三部分为音频编解码器。)容器可以存储视频、音频、字幕和元信息。网络上两种最常见的视频容器是 MP4 和 WebM。容器与文件类型相同——如果文件以 .mp4 扩展名结尾,则表示它使用的是 MP4 容器。但是,文件扩展名不会告诉您编解码器。网络上常用的视频编解码器示例包括 VP8、VP9、H.264 和 HEVC(H.265)。要在线播放视频,浏览器需要同时支持视频容器和编解码器。

浏览器对视频的支持非常混乱,这也是 YouTube 嵌入无处不在的部分原因,但这不适用于我们的用例。让我们看看值得考虑的视频格式。

容器

  • MP4 最初于 2001 年发布。它受所有网络浏览器支持,并且已经支持了相当一段时间。
  • WebM 于 2010 年发布。它适用于除 iOS Safari 之外的所有浏览器。

编解码器

  • H.264 编解码器 适用于所有浏览器
  • HEVC/H.265 是 H.264 的继任者,受 Safari、Edge 和 Chrome(从 105 版开始)支持。
  • VP9 是 VP8 编解码器的继任者。VP9 受所有支持 WebM 的浏览器支持。
  • AV1 编解码器自 2018 年起在 Chrome 中受支持,自 2019 年起在 Firefox 中受支持。它 尚未在 Edge 或 Safari 中推出。

使用 H.264 编解码器的 MP4 文件可以在任何地方使用,但它无法提供最佳质量或最小的文件大小。

AV1 尚未获得跨浏览器支持,但它于 2018 年发布,是目前最现代的编解码器。它已经被 Netflix、YouTube 和 Vimeo(至少对于某些视频和平台)使用。AV1 是一种专为互联网设计的免版税视频编解码器。AV1 由开放媒体联盟 (AOM) 创建,该联盟由 Google、Mozilla、Cisco、Microsoft、Netflix、Amazon 和 Intel 联合创立。Apple 现在也是成员之一,因此可以肯定地认为所有浏览器最终都会支持 AV1。Edge 正在“评估支持 AVIF 和 AV1 的选项”。

开发咨询公司 Evil Martians 最近重新设计的网站证明了 AV1 能够实现的文件大小减少。

如果要将较新的视频格式与旧版浏览器的回退功能一起使用,可以使用多个 <source> 元素。源元素的顺序很重要。在顶部指定理想的源,然后在后面指定回退。

<video autoplay loop muted playsinline>
  <source src="cats.webm" type="video/webm"> <!-- ideal -->
  <source src="cats.mp4" type="video/mp4"> <!-- fallhack -->
</video>

给定以上代码,将使用 cats.webm,除非浏览器不支持该格式,否则将显示 MP4。

如果想要包含多个 MP4 文件,但每个文件都使用不同的编解码器怎么办?在指定 type 时,可以包含 编解码器参数。对于任何不是硬核编解码器极客的人来说,语法都非常复杂,但它看起来像这样

<video autoplay loop muted playsinline>
  <source src="cats.mp4" type="video/mp4; codecs=av01.0.05M.08" >
  <source src="cats.mp4" type="video/mp4" >
</video>

使用以上代码,浏览器将选择 AV1(如果它可以播放该格式),否则将回退到普遍支持的 H.264。对于 AV1,codecs 参数始终以 av01 开头。下一个数字为 0(表示主配置文件)、1(表示高配置文件)或 2(表示专业配置文件)。接下来是两位数的级别编号。后面跟着字母 M(表示主层)或 H(表示高层)。很难理解这些内容的含义,因此您可以将 AV1 视频提供在 WebM 容器中,并避免完全指定编解码器。

大多数视频编辑软件不允许您导出为 AV1,甚至不允许导出为 WebM。如果要使用其中一种格式,则需要将视频导出为其他格式(例如 .mov),然后使用命令行工具 FFmpeg 进行转换。

ffmpeg -i yourSourceFile.mov -map_metadata -1 -c:a libopus -c:v librav1e -qp 80 -tile-columns 2 -tile-rows 2 -pix_fmt yuv420p -movflags +faststart -vf &quot;scale=trunc(iw/2)*2:trunc(ih/2)*2&quot; videoTitle.mp4

您应该使用尽可能高的分辨率源文件。显然,一旦图像质量丢失,就无法通过转换为更高级别的格式来提高它。使用 .gif 作为源文件不是理想的选择,因为 .gif 的视觉质量不是很好,但您仍然可以获得文件大小大幅减小的优势。

ffmpeg -i cats.gif -map_metadata -1 -an opus -c:v librav1e -qp 80 -tile-columns 2 -tile-rows 2 -pix_fmt yuv420p -movflags +faststart -vf &quot;scale=trunc(iw/2)*2:trunc(ih/2)*2&quot; cats.mp4

在 Mac 上,您可以使用 Homebrew 下载 FFmpeg。

brew install ffmpeg

这是一个在巧妙设计的 Oxide 网站 上使用网络设计中的视频的很好的例子。

如果要将视频用作背景并在其上放置其他元素,使用 <video> 比 CSS background-image 稍微更具挑战性,并且需要类似以下的代码

.video-parent {
  position: relative;
  width: 100vw;
  height: 100vh;
} 

.video-parent video {
  object-fit: cover;
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
}

<video> 元素是替换 GIF 的一个非常不错的选择,但它确实有一个不幸的副作用:它会阻止用户的屏幕进入睡眠状态,如 Microsoft Edge 浏览器的前产品经理在 这篇文章 中所述。

使用图像的好处

无论是动画 WebP 还是动画 AVIF 文件,使用图像而不是视频都有一些好处。

我不确定有多少人真正想要美化他们的 GIF,但使用 <picture> 元素确实打开了一些使用 <video> 难以实现的可能性。例如,您可以为亮模式和暗模式指定不同的动画。

<picture>
  <source srcset="dark-animation.avifs" media="(prefers-color-scheme: dark)">
  <img src="light-animation.avif" alt="">
</picture>

我们可能希望移动设备上的视频与桌面上的视频具有不同的纵横比。我们可以使用 CSS 裁剪图像的部分内容,但这似乎是一种浪费字节且有点杂乱无章的做法。使用媒体查询,我们可以根据屏幕尺寸或方向显示不同的动画图像文件。

<picture>
  <source type="image/avif" srcset="typeloop-landscape.avifs" media="(orientation: landscape)"">
  <img src="typeloop-portrait.avif" alt="">
</picture>

所有这些都可以通过视频实现——您可以使用 matchMedia 在 JavaScript 中执行任何媒体查询,并以编程方式更改 <video> 元素的 src

const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
if (mediaQuery.matches) {
  document.querySelector("video").src = "dark-animation.mp4";
}

我相信,只要有办法使用标记来做某事,就应该优先于使用 JavaScript 来做。

您可以使用 <image> 元素 在 SVG 内部使用光栅图像。这包括动画图像格式。在 SVG 内部的图像中,您无法执行许多使用 CSS 无法执行的操作,但是如果您将图像与 SVG 内部的矢量元素组合在一起,则可以获得不同的元素一起移动和缩放的优势。

<img> 元素具有 原生延迟加载 的优势。

<img loading="lazy" src="cats.avif" alt="cats">

如果需要占据整个屏幕的背景视频,定位 background-image 比 HTML <video> 元素更容易。

.background-video {
  background-image: url("coolbackground.webp");
  background-repeat: no-repeat;
  background-size: cover;
  height: 100vh;
  width: 100vh;
} 

如果要支持旧版浏览器,可以使用 <picture> 元素,并回退到动画 WebP 或仅适用于 Safari 的带有视频 srcimg,或者如果关心旧版浏览器,则可以回退到 APNG(动画 PNG)或 GIF。如果手动优化图像,则以这种方式使用多种图像格式可能不切实际;但如果您使用 Cloudinary 等服务,则相对来说非常简单。

<picture>
  <source type="image/avif" srcset="cats.avif">
  <img src="cats.webp">
</picture>

仍然没有很好的方法来为 CSS 背景指定回退图像。image-set 等效于 <picture> 元素,[但用于 background-image。不幸的是,目前只有 Firefox 支持 image-settype 属性。

.box {
  background-image: image-set(
    url("cats.avif") type("image/avif"),
    url("cats.webp") type("image/webp"));
}

此浏览器支持数据来自 Caniuse,其中包含更多详细信息。数字表示浏览器在该版本及更高版本中支持该功能。

桌面

ChromeFirefoxIEEdgeSafari
1138911317.0

移动/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari

12712712717.0

使用动画 WebP

WebP 图像格式由 Google 于 2010 年推出。WebP,包括动画 WebP,拥有广泛的浏览器支持

A cat flying through space leaving a rainbow trail
<img src="nyancat.webp" alt="A cat flying through space leaving a rainbow trail">

此浏览器支持数据来自Caniuse,其中包含更多详细信息。数字表示浏览器从该版本及更高版本开始支持该功能。

桌面

ChromeFirefoxIEEdgeSafari
32651816.0

移动/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari

1271274.2-4.314.0-14.4

使用动画 AVIF

WebP 现在已经十二岁了。更现代的 AV1 图像文件格式 (AVIF),于 2019 年发布,是网络上大多数用例的最佳图像格式。将 .gif 文件转换为 AVIF 可以将字节减少 90% 以上。

<img src="nyancat.avif" alt="A cat flying through space leaving a rainbow trail">

顾名思义,AVIF 基于 AV1 视频编解码器。与 WebP 一样,AVIF 可用于静态图像和动画。动画 AVIF 文件与 MP4 容器中的 AV1 视频之间没有太大区别。

您可以为 AVIF 动画添加阴影,例如:

filter: drop-shadow(2px 4px 6px black);

Safari、Firefox、Samsung Internet 和 Chrome 已经支持 AVIF。Firefox 只提供了对静态图像的支持,而不是动画 AVIF。Safari 从版本16.1开始支持动画。不幸的是,由于 Firefox 支持 AVIF,但不支持动画 AVIF,因此无法成功使用 <picture> 元素仅向支持动画的浏览器显示 AVIF。鉴于以下代码,Firefox 将显示 AVIF,但作为静态图像,而不是显示动画 WebP 版本

<picture>
  <source srcset="https://fonts.gstatic.com/s/e/notoemoji/latest/1f4a9/512.avif" type="image/avif">
  <img src="https://fonts.gstatic.com/s/e/notoemoji/latest/1f4a9/512.webp" alt="💩" width="32" height="32">
</picture>

AVIF 工具仍在改进。视频编辑软件无法让您将素材导出为动画 AVIF 或动画 WebP。您需要将其导出为其他格式,然后进行转换。在网站ezgif.com上,您可以上传视频文件或 .gif 并将其转换为 AVIF 或 WebP。您也可以使用 FFmpeg。使用Cloudinary,您可以上传视频文件或旧的 .gif 并将其转换为几乎任何您想要的格式,包括动画 WebP 和动画 AVIF。截至撰写本文时,图像转换应用程序 Squoosh 不支持动画 AVIF。

设计软件中的采用率仍然不足。在查看原型时,Figma 将播放设计中包含的任何动画 GIF。相比之下,对于 AVIF,您甚至无法导入或导出静态图像。

An error in Figma that says files failed to import.

使用带有 <img> 元素的视频

2018 年,Safari11.1 使开发人员能够使用视频文件作为 HTML <img> 元素的源。这在 Safari 中有效。

<img src="cat.mp4" alt="A Siamese cat walking in a circle">

Safari 支持 <video> 的所有编解码器都受 <img> 支持。这意味着您可以使用 MP4、H.264 和 HEVC。

在 Safari 中,视频文件还可以在 CSS 中的任何可以使用图像的地方使用,例如 background-imageborder-image

.video-border {  
  border: 40px solid transparent;
  border-image: url(abstract_bg_animation.mp4) 100 round;
}

Safari 中此功能的一个奇怪结果是,<video> 元素的海报图像也可以是视频。海报将自动播放即使您已阻止视频自动播放。Safari 声称此功能带来了性能优势,不仅优于使用 .gif 文件,而且优于使用 <video> 元素。根据Apple的说法

通过将您的视频放在 <img> 元素中,内容加载速度更快,电池电量消耗更少,并且性能更好。

Colin Bendell,O‘Reilly 的《高性能图像》的合著者,撰写了关于<video> 标签的缺点,以满足我们的用例。

<img> 标签不同,浏览器不会预加载<video> 内容。通常,预加载器仅预加载 JavaScript、CSS 和图像资源,因为它们对页面布局至关重要。由于 <video> 内容可以是任何长度——从微格式到长格式——<video> 标签会被跳过,直到主线程准备好解析其内容。这会将 <video> 内容的加载延迟数百毫秒。

[...]

更糟糕的是,许多浏览器假设 <video> 标签包含长格式内容。浏览器不会立即下载整个视频文件(如果最终没有观看整个视频,这会浪费您的蜂窝数据流量),而是首先执行 1 字节请求以测试服务器是否支持HTTP 范围请求。然后,它将进行多个范围请求,并使用各种块大小,以确保视频得到充分(但不过度)缓冲。结果是在浏览器甚至开始解码内容之前进行多次 TCP 往返,以及在用户看到任何内容之前出现明显的延迟。在高延迟的蜂窝连接上,这些往返会导致视频加载延迟数百或数千毫秒。

Chrome 已将其标记为“不会修复”——这意味着他们不打算永远支持此功能,原因有很多。但是,在 GitHub 上有一个开放问题,要求将其添加到 HTML 规范中,这将迫使 Google 采取行动。

尊重用户偏好

视频的好处是可以自动尊重用户的偏好。Firefox 和 Safari 允许用户阻止视频自动播放,即使它们没有任何音频。例如,以下是 Firefox 中的设置

firefox autoplay settings open in a modal.

用户仍然可以通过右键单击并在菜单中按下播放来决定观看某个视频,或者为特定网站上的所有视频启用自动播放。

Contextual menu for a video.

对于尚未禁用自动播放的用户,如果碰巧发现动画令人讨厌或分散注意力,能够选择暂停动画会很好(当不显示视频控件时,用户仍然可以右键单击以在菜单中显示暂停选项)。WCAG 可访问性指南中的成功标准2.2.2 暂停、停止、隐藏指出

对于任何自动开始、持续时间超过 5 秒且与其他内容并行显示的移动、闪烁或滚动信息,都必须有一种机制供用户暂停、停止或隐藏它,除非移动、闪烁或滚动是活动的一部分,并且在该活动中至关重要。

使用 <video> 元素,您无需任何额外的开发即可实现该标准。

还有一个“减少运动”用户设置,开发人员可以通过减少或删除 CSS 和 JavaScript 网页动画来尊重该设置。

macOS settings window for display accessibility with rediced motion checked.

您还可以使用它来显示静态图像而不是动画。这需要额外的代码来实现——并且您需要除了动画图像之外还需要托管一个静态图像。

<picture>
  <source
    srcset="nyancat.avifs"
    type="image/avif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <img src="nyancat.png" alt="Nyan cat" width="250" height="250" />
</picture>

还有一个缺点。当以这种方式使用 <picture> 元素时,如果用户已选中“减少运动”,则他们无法看到动画。仅仅因为用户更喜欢更少的动画,并不意味着他们永远不想任何动画——他们可能仍然希望能够选择加入并偶尔观看一个。与 <video> 元素不同,显示静态图像会剥夺这种选择。

检查渐进增强

如果要检查您的 <picture> 代码是否正常工作以及回退图像是否正在显示,可以使用 Chrome DevTools 中的“渲染”选项卡来关闭对 AVIF 和 WebP 图像格式的支持。鉴于所有浏览器现在都支持 WebP,这是一个非常方便的功能。

Chrome DevTools with Rendering panel open optons for disabling AVIF and WebP images.

虽然使用 CSS、JavaScript、DOM 元素、canvas 和 SVG 创建动画通常是最佳选择,但随着新的图像和视频格式提供比以前更小的文件,它们成为 UI 动画(而不仅仅是 nyancat 循环)的有用选项。对于一次性动画,AVIF 文件可能比导入整个动画库性能更好。

Circular badge that reads Match Accepted with an animated blue progress highlight going around it.
以下是一个使用视频进行 UI 的有趣示例,该示例来自 2017 年的英雄联盟网站

Lottie

Adobe的After Effects是一款流行的动画工具。使用名为Bodymovin的扩展程序,您可以将After Effects中的动画数据导出为JSON文件。

然后是Airbnb的开源动画库Lottie,它可以获取该JSON文件并在不同平台上渲染为动画。该库适用于原生iOS、Android和React Native应用程序,以及Web。您可以查看来自Google Home、Target和Walgreens等公司的示例

包含必要的依赖项后,您需要编写少量JavaScript代码才能运行动画。

<div id="lottie"></div>
const animation = bodymovin.loadAnimation({
  container: document.getElementById('lottie'),
  path: 'myAnimation.json',
  renderer: 'svg',
  loop: true,
  autoplay: true,
})

您可以选择更改这些设置,以便仅在事件发生后播放。

const lottieContainer = document.getElementById('lottie');
const animation = bodymovin.loadAnimation({
  container: lottieContainer, 
  path: 'myAnimation.json',
  renderer: 'svg',
  loop: true,
  autoplay: false,
  })
// Play the animation on hover
lottieContainer.addEventListener('mouseover', () => {
  animation.play();
});
// Stop the animation after playing once
animation.addEventListener('loopComplete', function() {
  animation.stop();
});

这是一个我从Lottiefiles.com(该网站是一个有用的网站,用于预览您自己的Lottie JSON文件动画,而不是需要安装After Effects,以及查找其他创意人员的动画)获取的可爱的小猫打字示例

您还可以以编程方式反向播放动画并更改播放速度。

如果您选择使用Lottie,则有一个Lottie的Figma插件,但它所做的只是将JSON文件转换为.gif,以便可以在原型模式下预览它们。

Lottie的性能如何?需要考虑库的大小——254.6KB(压缩后63.8KB)——以及JSON文件的大小。还需要考虑为SVG部分创建的DOM元素数量。如果遇到此问题,Lottie可以选择渲染到HTML <canvas>,但您需要使用JavaScript库的不同版本。

const animation = bodymovin.loadAnimation({
  container: document.getElementById('lottie'), 
  path: 'myAnimation.json',
  renderer: 'canvas',
})

Lottie并不是GIF的完整替代品。虽然After Effects本身通常与视频剪辑一起使用,并且Lottie可以渲染到HTML <canvas>,并且画布可以播放视频剪辑,但您不会将Lottie文件用于此目的。Lottie适用于高级2D动画,而不是视频。还有其他工具可以使用GUI创建复杂的Web动画,例如SVGatorRive,但我自己还没有尝试过。🤷‍♂️


我希望这篇文章有一个TL;DR。至少目前,还没有明确的赢家……