简化版动图技术,第二版

Avatar of Chris Coyier
Chris Coyier

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

您是否看过 这种巧妙的技术,它使用 <picture> 元素和 <source media=""> 根据 prefers-reduced-motion 媒体查询 来提供动画图像(或不提供)?

在我们 时事通讯 中分享了这一点后,我们收到了 Michael Gale 的一封有趣的回复。

那些喜欢动画 GIF 但又不想让 UI 到处缩放的人怎么办?他们现在是否被迫在内容和 UI 之间做出选择?

我认为这是一个非常有趣的问题。

此外,如今每当我看到 <img src="gif.gif"> 时,我的大脑就会被触发进入 那么 MP4 呢?! 区域,因为我已经充分相信,在网络上,视频在各个方面都优于 GIF。事实证明,某些浏览器支持在 <img> 元素中直接使用视频,并且,信不信由你,您 可以为此编写回退,并且——请鼓掌——还可以使用 <picture> 元素!

让我们尝试将所有这些东西结合起来。

添加 MP4

最简单的方法是添加另一个带有视频的 <source>。这意味着我们需要三个源媒体文件。

  1. prefers-reduced-motionreduce 时,回退到非动画图形。
  2. 动画 GIF 作为默认值。
  3. 如果支持回退,则使用 MP4 视频替换 GIF。

例如

<picture>
  <source srcset="static.png" media="(prefers-reduced-motion: reduce)"></source>
  <source srcset="animated.mp4" type="video/mp4">
  <img srcset="animated.gif" alt="animated image" />
</picture>

在 Chrome 中的默认情况下,只会下载和显示 GIF。

Chrome DevTools showing only gif downloaded

在 Safari 中的默认情况下,只会下载和显示 MP4

Safari DevTools showing only mp4 downloaded

如果您在 Chrome 或 Safari 中激活了 prefers-reduced-motion: reduce(在我的 Mac 上,我转到 系统偏好设置辅助功能显示降低动画效果),则两个浏览器只会下载静态 PNG 文件。

Chrome DevTools showing png downloaded

我测试了 Firefox,它似乎不起作用,而是继续下载 GIF 版本。Firefox 似乎支持 prefers-reduced-motion,但也许它在 <source> 元素上尚不支持?我不确定那里发生了什么。

提供单个动画源并使用工具从该源生成其他源,这会不会很酷?我敢打赌,您可以使用类似 Cloudinary 的东西将其连接起来。

添加一个切换按钮以显示动画版本

正如 Michael Gale 所提到的,仅仅因为您启用了降低动画效果的切换按钮就完全无法看到动画版本,这似乎很可惜。

使用 <button> 来使用 JavaScript 取消媒体查询并强制浏览器显示动画版本应该很容易。

我相当肯定,无法以声明方式在 HTML 中执行此操作。我们也不能将此按钮放在 <picture> 标记内。即使 <picture> 不是替换元素,浏览器仍然会感到困惑并且不喜欢它。相反,它根本不会呈现它。没什么大不了的,我们可以使用包装器。

<div class="picture-wrap">
  
  <picture>
     <!-- sources  -->
  </picture>

  <button class="animate-button">Animate</button>

</div>

我们可以在图像顶部某个位置放置按钮。这只是一个任意选择——您可以将其放在任何位置,或者甚至可以使整个图像都可点击,只要您认为可以向用户解释即可。请记住,仅当相同的媒体查询匹配时才显示按钮。

.picture-wrap .animate-button {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .picture-wrap .animate-button {
     display: block;
  }
}

单击(或点击)按钮时,我们需要删除媒体查询以通过下载动画源来启动动画。

let button = document.querySelector(".animate-button");

button.addEventListener("click", () => {
  const parent = button.closest(".picture-wrap");
  const picture = parent.querySelector("picture");
  picture.querySelector("source[media]").remove();
});

这是实际操作

查看 CodePen 上 Chris Coyier 的作品
降低动画效果技术 PLUS!
(@chriscoyier)
CodePen 上。

也许这是一个好的组件?

我们可以使用 Web组件 自动包含按钮、按钮样式和按钮功能。嘿,为什么不呢?

查看 CodePen 上 Chris Coyier 的作品
降低动画效果技术作为 Web 组件
(@chriscoyier)
CodePen 上。