9月7日-8日,相约 2023 腾讯全球数字生态大会!聚焦产业未来发展新趋势! 了解详情
写点什么

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

  • 2018-07-29
  • 本文字数:0 字

    阅读完需:约 1 分钟

概要

  • 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 Portis , Jer Noble , Jon Davis , Doron 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。要这么做,你需要基于 AcceptUser-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

感谢徐川对本文的审校。

活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

2018-07-29 18:176629

评论 2 条评论

发布
用户头像
受益匪浅
2019-07-01 19:36
回复
没有更多了
发现更多内容

论渗透信息收集的重要性

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

Deco 智能代码技术揭秘:设计稿智能生成代码

凹凸实验室

机器学习 AI 大前端 低代码

移动支付与支付安全SDL

明亮安全观

网络安全 信息安全 数据安全 支付安全 交易安全

“元宇宙”来了 城市会消亡吗?

CECBC

元宇宙所带来价值共识的历史回归

CECBC

雪花算法对System.currentTimeMillis()优化真的有用么?

秦怀杂货店

分布式 算法 雪花算法

Nocalhost 成功加入 CNCF 沙箱

科技热闻

区块链技术及其军事应用

CECBC

[Pulsar] 按照KeyHashRange读取消息

Zike Yang

Apache Pulsar 11月日更

创新模式驱动生产力提升,融云社交场景化 SDK 探索

融云 RongCloud

直播 sdk 语聊房 场景化

Taro 3.4 beta 发布: 支持 Preact 为应用开辟更多体积空间

凹凸实验室

taro 大前端 React HarmonyOS

【架构实战营】模块五

Henry | 衣谷

架构实战营

APISIX-Datadog 插件发布,助力用户提高系统的可观测性

API7.ai 技术团队

云原生 可观测性 API网关 APISIX Datadog

【DevKit黑科技揭秘】│深入浅出DevKit性能调优,让系统“瓶颈”无处遁形

Geek_32c4d0

不要累死自己,也不要卷死别人。

石云升

内卷 职场经验 11月日更

技术管理哲学随笔:如果空降,你会怎么做

dclar

CTO 技术管理 管理经

一网成擒全端涵盖,在不同架构(Intel x86/Apple m1 silicon)不同开发平台(Win10/Win11/Mac/Ubuntu)上安装配置Python3.10开发环境

刘悦的技术博客

Python ubuntu Mac Python3 win11

30 K8S之Deployment控制器

穿过生命散发芬芳

k8s 11月日更

在线文本字符串批量替换工具

入门小站

工具

社交泛娱出海新引擎,融云「六化」能力助开发者轻装上阵

融云 RongCloud

游戏出海 出海社交 出海

WICC 广州高峰对话:为开发者标注「航海地图」

融云 RongCloud

开发 游戏 社交 泛娱乐 出海

总决赛金银铜奖揭晓,2021信创“大比武”鲲鹏赛道圆满落幕!

科技热闻

Zillow“炒房”失败,算法神话破灭了吗?

脑极体

如何使用 Kubernetes 监测定位慢调用

阿里巴巴云原生

阿里云 Kubernetes 云原生 监控工具

读《区块链技术及应用第二版》华为区块链发展思路、双引擎战略及华为区块链特点和使用有感

孙叫兽

区块链 华为链 华为区块链服务

ONES Talk | 我们为什么选择最难走的软件之路

万事ONES

SaaS ONES

恒源云(GPUSHARE)_卷积神经网络的工作原理

恒源云

深度学习

TypeScript 之基础入门

冴羽

JavaScript typescript html5 翻译 大前端

hw5-微博评论高性能高可用

WWH

架构实战营

文章目录 [Index]

dclar

大数据 技术 管理 操作系统 中间件

.NET 中缓存的实现

喵叔

11月日更

  • 扫码添加小助手
    领取最新资料包
< img >标签动态图片的进化:不是GIF,胜过 GIF_语言 & 开发_BrotherZhao_InfoQ精选文章