皇上,还记得我吗?我就是1999年那个Linux伊甸园啊-----24小时滚动更新开源资讯,全年无休!

< img >标签动态图片的进化:不是 GIF,胜过 GIF

作者 BrotherZhao

概要

  • GIF 确实很好,但是却有着严重的图像质量损失和性能损耗。
  • 以  <video> 替换 GIF 效果更好,但是会造成性能缺陷: 无法预加载,需要范围请求
  • 现在可以在 Safari Technology Preview 中使用 <img src=".mp4"> 标签了。
  • 初步测试结果显示, <img> 标签中的 MP4 比同等条件下的 GIF 播放快 20 倍、解码快 7 倍——而文件尺寸仅为 1/14 !
  • 背景 CSS 视频和响应式视频(Responsive Video)终于可以独立为一个“东西”了。
  • 动态照片(cinemagraphs)终于摆脱了 GIF 的固有弊病。
  • 很期待其他浏览器快速跟进:本文在 Chrome 中打开有 46 MB,但是在 Safari Technology Preview 中只有 2 MB。

特别致谢:Eric PortisJer NobleJon DavisDoron Sherman, 和 Yoav Weiss.

引言

很多人对 GIF 都是既爱又恨。

Safari Tech Preview 的出现可能会改变这一切,让人们对 GIF 全都是爱。

实际上,动画 GIF 的用法脱离了 GIF 的本意,比如 最初的 GIF89a 声明指出

GIF 格式(Graphics Interchange Format)并非为动画设计的平台,尽管可以在有限程度上如此操作。

但是 GIF 却发展成了 动态照片表情包 和创意 展示 的绝佳工具。当然了,这些绝佳应用都是有代价的。动画 GIF 的 web 端性能十分差劲:GIF 体积庞大、耗费移动蜂窝流量、需要更多的 CPU 和内存、 导致重绘 并严重降低电池性能。一般而言,GIF  是 H.264 视频体积的 12 倍,在浏览器中的加载和播放要消耗 2 倍的电量 。结果,消耗如此多的资源,得到的效果却不尽人意——GIF 的 256 色的限制导致很多 GIF 特别难看(尽管 有一些看起来很棒)。

小孩子通常都会很喜欢 GIF ——但是他们却不会明白,为什么用来看 GIF 的设备的电池总是很快就没电。

GIF 有很多优势:迅速响应浏览器的请求、自动播放而且循环播放、没有声音。这也意味着 GIF 会比较简短。市场调研表明 ,用户更喜欢一分钟以内的微视频和动态图片,而不是很长的视频和静态图片。从这里来看,GIF 对于用户体验是很好的。

如何让人们从对 GIF 既爱且恨转变为十分喜爱 Gif 的呢?(这里为了区分而故意改变了大小写)。

在最新的 Safari Tech Preview 中,多亏了 Jer Noble 的辛苦工作,人们可以直接在 <img> 标签中加载 MP4 文件了:这个用例不是很长的视频,而是简短的、无声的、循环播放的视频,就像 GIF 一样。你可以自己先看一下:

<img src="rocky.mp4">

这个效果很棒。这对于企业和个人用户,尤其是就 Web 性能而言,都是很了不起的。

但是我们已经有 <video > 标签了啊?

正如 很多人指出的 那样,直接采用 <video > 标签会比使用 GIF 的性能要好得多。这也是 Twitter 在 2014 年宣布增加对动画 GIF 的支持而不增加对 GIF 的支持的原因 。Twitter 将 GIF 转换为 MP4 文件,并通过 <video > 标签进行传输。因为所有的浏览器都支持 H.264 视频格式,所以这个转换很简单。

<video autoplay loop muted inline>
  <source src="eye-of-the-tiger-video.webm" type="video/webm">
  <source src="eye-of-the-tiger-video.mp4" type="video/mp4">
  <img src="eye-of-the-tiger-fallback.gif"/>
</video>

将动画 GIF 转换为 MP4 十分简单,只需要运行一行命令就行可以:ffmpeg -i source.gif output.mp4

然而,并不是所有人都能拆解自己的内容管理系统并将 <img> 转换为 <video > 标签。就算你可以做到,这里也存在 3 个问题

1. 浏览器处理 <video > 标签的速度很慢

正如 Goug Sillars 最近在 HTTP Archive 的一篇文章指出 ,使用 <video > 标签会造成很大的性能损耗。

与 <img> 标签不同的是,浏览器不会预先加载 <video> 标签内容。一般而言,浏览器只会预加载 JS、CSS 和图像资源,因为他们对于页面展示是不可或缺的。由于 <video> 标签的内容尺寸不一,所以 <video> 标签是在主线程开始准备展示内容的时候才会加载的。这样就导致 <video> 标签加载延迟数百微秒。

例如, 速度峰会页面(Velocity conference page) 上方的视频需要 5 秒才能加载,而他是 此页面中的第 27 个加载项 ,是在 Start Render 请求之后,也在网页字体加载之后。

更糟糕的是,很多浏览器认为 <video> 标签包含着很长格式的内容。为了防止在不想看完视频的情况下浪费移动流量,这些视频不是一次性加载完毕的。浏览器会首先执行一个 1 比特的请求,以测试服务器是否支持 HTTP 范围请求 。然后,会有一系列不同大小的范围请求,以保证视频得到足够而不过分的缓冲。这样的结果就是,在浏览器开始解码内容以前就发生了多个 TCP 往返循环,显著延迟了用户看到视频的进程。在移动网络有较高延迟的情况下,这些往返循环可能导致视频播放有上百甚至上千微秒的延迟。

典型的 JS 视频播放器比本地的 <video> 标签表现更差劲。通常将视频嵌入网站的最简单的方法是利用本地化服务,就像 YouTube 和 Vimeo 做的那样,这样能够避免视频解码、播放和 UX 等复杂工作。这个方法很好,但是对于微视频或者像前述网站顶部的关键内容来说,只是徒增延迟而已——原因不外乎是 JS 播放器和这些本地服务需要注入的支撑资源(css/js/jpg/woff)。在 <video> 之外,浏览器不得不下载、评估和执行 JS 播放器程序——然后才能播放视频。

很多人都喜欢 Loki 夹克,但是看一下 Loki 美国官网——他们的首页视频寄存在 Vimeo 服务器:

仔细看就能发现 JS 播放器在 DOM 完成之后立马请求了,但是很久之后才完全加载并开始播放视频。

WPT Results

2. 无法右键保存视频

大多数长篇视频内容都是基于 JS 播放器进行分发的——影像日志、电视、电影。通常这些播放器为用户提供了很方便的分享链接和书签工具,这样用户就可以随时返回 YouTube 或者其他任何地方并再次找到这个视频。作为对比,微视频内容——比如表情包和图片动画——通常不是经由播放器传递的,用户希望能够下载 GIF 并分发给朋友,就像他们对网络上其他图片进行的操作一样,比如“这只跳舞的猫咪太可爱了,我必须分享给所有的好友!”

如果你用的是 <video> 标签,那用户就不能右键另存为了。而前面提到的跳舞的猫咪也就是出色却让人失望了。

3. 自动播放被滥用

最后,采用  <video> 标签和 MP4 而不是 <img> 标签和 GIF,就会发生在你浏览网页时突然蹦出猫鼠游戏的视频,这就是为了吸引用户注意而滥用 <video autoplay> 自动播放属性的案例。移动浏览器都忽略或者禁用了自动播放属性,需要全屏才会启动这一属性。在过去几年中,苹果谷歌 都放松了这方面的限制,允许 <video> 下类似 GIF 的内容自动播放。

然而,广告厂商又在滥用这一特性,引发了更加严格的限制:如果要用自动播放 <video> 的功能,必须将内容属性设置为静音 <muted> 或者完全去除声轨。

但是我们已经有了动态 WebP 和动态 PNG 啊!

GIF 并不是唯一的具有动画小姑的图片格式。WebP 和 PNG 也都支持动画功能。但是,与 GIF 类似的是,他们都不是为动画设计的。这就导致,和专注于视频编码的格式如 H.264、H.265、VP9 和 AV1 相比,他们的动画文件体积巨大。

动态 PNG 在各种浏览器中得到了广泛支持,但是他也有 GIF 存在的色彩问题,同时依旧不能高效压缩视频。

动态 WebP 能好一些,但是与真正的视频格式相比,还是有很多问题。除了不具备标准格式外,动态 WebP 缺少色度子采样和宽域支持。更进一步地,动态 WebP 的支持生态十分破碎,并非所有的 Android、Chrome 和 Opera 都支持动态 WebP,甚至浏览器都把支持 WebP 作为一项特性来打广告:Chrome 42、Opera 15+ 和 Android 5+ 才行。

所以尽管动态 WebP 比 动态 GIF 和 PNG 的压缩效率要高,但我们还可以做得更好(见上面的图片压缩对比)。

自己测试一把

Having our cake and eating it too

Safari Technology Preview 为 <img> 标签增加了真正的视频功能(如 MP4),修复长期存在的性能和 UX 问题。现在,我们的微视频可以做到体积小、效率高(正如通过 <video> 标签传输的 MP4 文件那样),并且可以轻松地预加载、自动播放和分享(就像分享 GIF 那样)。

<img src="ottawa-river.mp4">

那么具体说来,如此操作究竟能有多么快速?打开浏览器的开发者工具,将 Safari Technology Preview 和其他浏览器对比一下吧:

很不幸的是, Safari 在 WebPageTest 上表现欠佳,而要打造可信的 benchmark 也非朝夕之功。与之类似的,Tech Preview 的使用量还很低,所以基于 RUM 工具进行性能比对也还不太实际。

然而,我们在两方面可以有所作为。一是对比最初文件的体积,二是利用 Image.decode() 命令,测试不同资源对于设备的影响。

节省流量

首先要说明的是,图片体积就表征了流量节省情况。为了进行对比,实验者将  giphy.com 前 100 的动图 GIF 分别转换为 vp8/vp9/webp/h264/h265 格式 .

声明:这些结果仅可作为方向示意。每个解码器都可以做更多调试,正如可以看到的, vp9 要比默认的 vp8 输出差很多。还需要进行更详细的、把 SSIM 考虑在内的测试。

以下是此次测试的 中位数 (p50) 结果 :

格式 尺寸中位数 变化百分比中位数
GIF 1,713KB
WebP 310KB -81%
WebM/VP8 57KB -97%
WebM/VP9 66KB -96%
WebM/AV1 TBD
MP4/H.264 102KB -93%
MP4/H.265 43KB -97%

WebP 的体积比 GIF 要小,但是其他任何形式都比 WebP 还要小。这没什么奇怪的,因为这些新的视频编码就是为在线视频流高度优化的。H.265 正如预期的 AV1 一样表现不错。

这样的优势不仅是传输更快,而且是 为终端用户大量节省费用

总而言之,在 <img> 标签中使用视频在移动网络情况下速度更快。

解码和视觉效果的提升

下面要考虑的是解码和浏览器端的播放效果。H.264 和 H.265 的优势是硬件解码。

如何进行测量?

因为浏览器尚未完善 首屏图片 API,可以采用 Steve Souder 的 User Timing and Custom Metric strategy 作为近似手段,评估图片合适向用户展示。他并不测量帧频,但是却大致告诉人们第一帧何时播放。更好的是,可以使用新采纳的 Image.decode() 测量解码性能。在下方的测试页面中,实验者在 <img> 标签中注入了一张特定的 GIF 和 MP4 100 次,并对比了解码和绘图性能。

let image = new Image;
t_startReq = new Date().getTime();
document.getElementById("testimg").appendChild(image);
image.onload = timeOnLoad;
image.src = src;
return image.decode().then(() => { resolve(image); });

结果令人印象深刻。在实验者所用的 2017 MacBook Pro 进行不联网本地测试的情况下,GIF 比 MP4 要多花 20 倍的时间才能绘制出第一帧(由 onload 事件信号而来),前者的解码时间是后者的 7 倍。

很好奇嘛? 复制这个项目 ,自己测试下吧。需要注意的是,联网会对这个 GIF vs MP4 的试验结果造成扭曲。尤其是,在最后一个比特结束之前,解码就已经开始了,这样在传输、播放和解码之前的差距就变得小多了。这表明,节省流量可以大幅度提高用户体验。然而,仅在本地机器进行测试,你就能够发现,视频在节能方面也有着极佳的表现。

如何改进?

既然 Safari Technology Preview 已经支持这样的设计模式了,人们该如何利用这一功能,而不必在不支持的浏览器上显示破碎的图片?好消息是这个其实很简单。

方法 1 :使用响应式图片

理想情况下,最简单的是利用 HTML5 中 <picture> 标签的 <source type> 特性:

<picture>
  <source type="video/mp4" srcset="cats.mp4">
  <source type="image/webp" srcset="cats.webp">
  <img src="cats.gif">
</picture>

其实事情就到此为止了。然而,Safari 中有一个 WebKit bug 导致预加载器会下载第一个 <source>,而无关乎类型声明。主 DOM 加载器能够发现这一错误并选择正确的加载,但是这一损害是不可逆的:预加载器充分利用了机会将图片下载下来,而更重要的是这浪费了流量。好消息是,有人上报了这一 Bug,应该会在 Safari TP 45 中得到修复。

简言之,在 Safari 下一版本达到 90% 的用户基数之前,不推荐使用 <picture> 和 <source type>

方法 2:使用 MP4、动画 WebP 和 GIF 回调

如果你不想改变 HTML 标记,你也可以使用 HTTP 将 MP4 附带内容协议发送给 Safari。要这么做,你需要基于 Accept 和 User-Agent 的 Header 生成动态图片(跟从前一样)和 Vary 回复的多个拷贝。

在 WebKit BUG 179178 发布后,这一切简单多了。你可以使用 Accept: video/* 进行测试(就像之前使用 Accept: image/webp 进行测试一样)。但是不同的浏览器有着不同的支持类型,具体如下

浏览器 接受的 Header 响应
Safari TP41+ H.264 MP4
Accept: video/mp4 H.264 MP4
Chrome 42+ Accept: image/webp aWebP
Opera 15 Accept: image/webp aWebP
Accept: image/apng aPNG
Default aGif

在 Nginx 中,将与下述类似:

map $http_user_agent $mp4_suffix {
    default   "";
    "~*Safari/605"  ".mp4";
}

location ~* .(gif)$ {
          add_header Vary Accept;
          try_files $uri$mp4_suffix $uri =404;
}

当然了,不要忘记利用 Vary: Accept, User-Agent 告诉他们分别缓存每项响应。实际上,你应该将 Cache-Control 设置为私密属性,并利用 TLS 来保证不太熟练的 ISP 性能提高代理不会缓存内容:

GET /example.gif HTTP/1.1
Accept: image/png; video/*; */*
User-Agent: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/605.1.13 (KHTML, like Gecko) Version/11.1 Safari/605.1.13

…

HTTP/1.1 200 OK
Content-Type: video/mp4
Content-Length: 22378567
Vary: Accept, User-Agent

方法 3:使用 RESS 和回调 <video> 标签

如果你可以自由操纵 HTML,你可以采用 RESS 技术(Responsive-Server-Side)。这样可以将浏览器的检测逻辑移动到 HTML 的输出中。

例如,对于 PHP 你可以这么做:

<?php if(strlen(strstr($_SERVER['HTTP_USER_AGENT'],"Safari/605")) <= 0 ){ // if not firefox ?>
<img src="example.mp4">
<?php } else {?>
<img src="example.gif">
<?php }?>

如上文所示,一定记得将 Vary: User-Agent 的响应提供给 CDN 供应商,告诉他们,你的 HTML 有不同版本的缓存内容。有些 CDN 厂商自动支持 Vary 抬头,而其他厂商需要经过简单的 CDN 配置才可以。

额外奖励:不要忘记删除音轨

现在既然你决定不将 GIF 转为 MP4 而是将 MP4 转为 GIF,需要记住的是,删除音轨以节省体积。既然已经知道这些动画都将是静音播放的,所以把声音和其他不必要的都删除就好了。对于 ffmpeg 最简单的方式是:

ffmpeg -i cats.mp4 -vcodec copy -an cats.mp4

是否有体积限制?

在撰写本文期间,Safari 会无区分地下载所有 <img> 标签中的视频,无论体积大小如何。一方面,这会帮助提高浏览器性能,所以是需要的;另一方面,如果向用户推送了一条 120 分钟的视频,这就很可怕了。实验者测试了不同体积的视频,发现只要用户在线,所有的视频都会下载下来。所以,要对用户友善些:如果想推送长视频,从性能考虑还是用 <video> 标签吧。

下一步是什么?交互式视频和背景视频

既然已经可以通过 <img> 标签传送视频, 那就会有很多新的用例了,比如交互式视频和背景视频。

比如,可以将 MP4 放在 srcset 中,利用 Client Hints 和 Content-DPR 给出不同的反应类型,并利用 <picture media> 添加艺术效果——这里有无限可能。

<img src="cat.mp4" alt="cat"
  srcset="cat-160.mp4 160w, cat-320.mp4 320w, cat-640.mp4 640w, cat-1280.mp4 1280w"
  sizes="(max-width: 480px) 100vw, (max-width: 900px) 33vw, 254px">

CSS 中的视频 background-image: url(.mp4) 同样也会奏效。

<div style="width:800px, height: 200px, background-image:url(colin.mp4)"/>

结论

Safari Technology Preview 为 <img> 标签引入视频功能,能够实现与 GIF 类似的良好体验,同时可以避免 GIF 文件的性能和质量损耗。对于用户、开发者、设计师和网络人员来说,这一功能真是非常赞。这一升级除了带来巨大的性能提升之外,还打开了媒体和电商企业数年来长期渴求的很多新的用例。希望其他浏览器能够马上跟进:谷歌、微软、火狐、三星……该你们接招了。

阅读英文原文Evolution of < img >: Gif without the GIF

转自 http://www.infoq.com/cn/articles/animated-gif-without-the-gif

分享到:更多 ()