长话短说
- GIF 很棒,但质量和性能很差
- 使用video用替换 Gifs可能会好,但有性能缺点:没有预加载和使用范围请求
- 现在您可以
<img src=".mp4">
使用 Safari 技术预览版 - 早期结果显示,标签中的 mp4
<img>
显示速度比同等 GIF 快 20 倍,解码速度快 7 倍,而且文件大小仅为其 1/14! - 背景 CSS 视频和响应式视频现在可以成为一个"东西"。
- 最后 -- 没有 GIF 缺点的电影照片!现在我们等待其他浏览器赶上
介绍
既喜欢又讨厌 GIF 动画。
Safari 技术预览版改变了这一切。现在我非常喜欢动画"GIF"。
动画 GIF 是一种黑客手段。引用原始 Gif89a 规范:
笔记:图形交换格式并非旨在作为动画平台,尽管它可以以有限的方式完成。
但它们已经成为电影摄影、模因和创意表达的绝佳工具。然而,所有这些精彩都是有代价的。动画 Gif 对于网络性能来说非常糟糕。它们体积巨大,影响蜂窝数据费用,需要更多的 CPU 和内存,导致重新绘制,并且是电池杀手。通常,Gif 的文件比 H.264 视频大 12 倍,在浏览器中加载和显示所需的量是 H.264 视频的 2 倍。我们将所有这些资源都花在了一些看起来不太好的东西上------GIF 256 颜色的限制常常使 GIF 文件看起来很糟糕(尽管有一些很酷的解决方法)。
我女儿很喜欢它们,但她不明白为什么她的电池总是没电。
Gif 有很多优点:它们由浏览器预加载器立即请求,它们自动播放和循环,而且它们是无声的!隐含地它们也更短。市场 研究表明,与较长形式的视频和静态图像相比,用户对微形式视频(< 1 分钟)和动态图片(具有微妙运动的静态图像)的参与度更高,并且通常更喜欢它们。动画 Gif 非常适合用户体验。
那么我是如何从爱/恨 Gif 到爱/爱"Gif"的呢?
在最新的 Safari 技术预览版中,由于Jer Noble的辛勤工作,我们现在可以在标签中使用 MP4 文件<img>
。预期的用例不是长视频,而是微格式、静音、循环视频------就像动画 Gif 一样。你自己看一下:
css
<img src="rocky.mp4">
很酷!这在很多方面都非常棒------对于业务、可用性,尤其是网络性能!
额...但我们已经有<video>
标签了?
正如许多人已经指出 的那样,使用<video>
标签比使用动画 Gif 的性能要好得多。这就是为什么 Twitter 在 2014 年以不添加 GIF 支持的方式添加了动画 GIF 支持。相反,Twitter 将 Gif 即时转码为 MP4,并在<video>
标签内传递它们。由于现在所有浏览器都支持 H.264,因此这是一个非常简单的过渡。
ini
<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
然而,并不是每个人都能彻底改造他们的 CMS 并转换<img>
为<video>
.即使可以,这种传送类似 Gif 的微格式视频的方法也存在三个问题:
-
浏览器性能缓慢
<video>
正如Doug Sillars 最近在 HTTP Archive 帖子中指出的那样,使用该标签时会产生巨大的视觉呈现性能损失
<video>
。与标签不同
<img>
,浏览器不会预加载<video>
内容。通常预加载器仅预加载 JavaScript、CSS 和图像资源,因为它们对于页面布局至关重要。由于<video>
内容可以是任何长度(从微格式到长格式),因此<video>
会跳过标签,直到主线程准备好解析其内容。这会导致内容加载延迟<video>
数百毫秒。例如,Velocity 会议页面顶部的英雄视频仅在页面加载后 5 秒内被请求。这是第 27 个请求的资源,甚至在加载 Web 字体后、开始渲染之后才请求它。
更糟糕的是,许多浏览器假设
<video>
标签包含长格式内容。浏览器不会立即下载整个视频文件(如果您最终没有观看整个视频,这会浪费您的蜂窝数据计划),浏览器将首先执行 1 字节请求来测试服务器是否支持HTTP Range Requests。然后,它将遵循不同块大小的多个范围请求,以确保视频得到充分(但不会过度)缓冲。结果是在浏览器甚至可以开始解码内容之前进行多次 TCP 往返,并且在用户看到任何内容之前出现明显的延迟。在高延迟蜂窝连接上,这些往返链接可能会使视频加载延迟数百或数千毫秒。还有什么比原生元素的性能更差呢
<video>
?典型的 JavaScript 视频播放器。通常,在网站上嵌入视频的最简单方法是使用 YouTube 或 Vimeo 等托管服务,并避免视频编码、托管和用户体验的复杂性。这通常是一个好主意,但对于微格式视频或英雄视频等关键内容,由于 JavaScript 播放器和这些托管服务注入的支持资源 (css/js/jpg/woff),它只会增加延迟。除了<video>
标记之外,您还强制浏览器下载、评估和执行 JavaScript 播放器,然后视频才能开始加载。正如许多人所知,我喜欢我的 Loki 夹克,因为它内置手套、巴拉克拉法帽和尺寸适合头盔的兜帽。但看看 Loki USA 主页 -- 它使用了 Vimeo 上托管的精彩英雄视频:
如果仔细观察,您会发现播放器的 JavaScript 实际上是在 DOM Complete 后不久请求的。但直到很久以后它才完全加载并准备好启动视频流。
查看WPT 结果
-
您无法右键单击并保存视频
大多数长视频内容(视频博客、电视、电影)都是通过基于 JavaScript 的播放器传送的。通常这些播放器为用户提供方便的"立即分享"链接或书签工具,以便他们可以返回 YouTube(或其他地方)并再次找到视频。相比之下,微形式内容(例如表情包和动态图片)通常不通过播放器提供,用户希望能够下载动画 Gif 并将其发送给朋友,就像处理网络上的任何图像一样。跳舞猫的表情包太有趣了------我必须和我所有的朋友分享!
如果您使用
<video>
标签来提供微格式视频,用户将无法右键单击、单击并拖动或用力触摸并保存。他们像猫一样跳舞的喜悦变成了令人沮丧的用户体验惊喜。 -
自动播放滥用
最后,使用
<video>
标签和 MP4 代替<img>
标签和 GIF 会让您陷入浏览器和不合情理的广告供应商之间正在进行的猫鼠游戏,他们滥用该<video autoplay>
属性来吸引用户的注意力。从历史上看,移动浏览器忽略了自动播放属性和/或拒绝内嵌播放视频,要求它们全屏显示。在过去的几年里,苹果和谷歌都放松了对内嵌、自动播放视频的限制,允许使用标签提供类似 Gif 的体验<video>
。但广告网络再次滥用了这一点,造成了进一步的限制:如果您想自动播放<video>
标签,您需要标记内容muted
或一起删除音轨。
...但我们已经有了动画 WebP!还有动画PNG!
GIF格式并不是唯一支持动画的静态图像格式。 WebP 和 PNG 也支持动画。但是,与 GIF 一样,它们不是为了动画而设计的,与 H.264、H.265、VP9 和 AV1 等专用视频编解码器相比,它们会产生更大的文件。
动画 PNG 现已在所有浏览器中得到广泛支持,虽然它解决了 GIF 的调色板限制,但它仍然是一种低效的视频压缩文件格式。
动画 WebP 更好,但与真正的视频格式相比,它仍然存在问题。除了没有正式的标准之外,动画 WebP 还缺乏色度二次采样和广色域支持。此外,支持生态系统是支离破碎的。甚至并非所有版本的 Android、Chrome 和 Opera 都支持动画 WebP------尽管这些浏览器宣传支持Accept: image/webp
.您需要 Chrome 42、Opera 15+ 或 Android 5+。
因此,虽然动画 WebP 的压缩效果比动画 GIF 或 aPNG 好得多,但我们可以做得更好。 (请参阅下面的文件大小比较)
我们的蛋糕
通过将真正的视频格式(如 MP4)包含在<img>
标签中,Safari 技术预览版解决了这些性能和用户体验问题。现在,我们的微格式视频可以小而高效(如通过标签传送的 MP4 <video>
),并且可以轻松预加载、自动播放和共享(如我们的老朋友,动画 GIF)。
ini
<img src="ottawa-river.mp4">
那么这会快多少呢?拉起开发者工具,看看Safari Technology Preview和其他浏览器的区别:
不幸的是,Safari 与 WebPageTest 的配合不佳,并且创建可靠的基准测试非常复杂。同样,Tech Preview 的使用率相当低,因此与 RUM 工具进行性能比较尚不切实际。
然而,我们可以做两件事。首先,比较原始字节大小,其次,使用Image.decode() Promise 来衡量不同资源对设备的影响。
节省字节数
首先,节省字节大小。为了进行比较,我从giphy.com获取了热门 100 个动画 GIF,并将它们转换为 VP8、VP9、WebP、H.264 和 H.265。
笔记: 注意: 这些结果仅应被视为方向性的!每个编解码器都可以进行更多调整;正如您所看到的,这里默认的 VP9 编码设置比默认的 VP8 输出要差得多。应该进行更全面的研究,考虑通过 SSIM 测量的视觉质量。
以下是转换结果的中位数 (p50) :
格式 | 字节 p50 | p50 变化百分比 |
---|---|---|
动图 | 1,713KB | |
网络P | 310KB | -81% |
WebM/VP8 | 57KB | -97% |
WebM/VP9 | 66KB | -96% |
网络M/AV1 | 待定 | |
MP4/H.264 | 102KB | -93% |
MP4/H.265 | 43KB | -97% |
所以,动画 WebP 几乎总是比动画 GIF 小------但任何视频格式都会小得多。这不应该让任何人感到惊讶,因为现代视频编解码器针对在线视频流进行了高度优化。 H.265 的表现非常好,我们应该期望即将推出的 AV1 也能表现出色。
这样做的好处不仅是更快的传输速度,而且还可以为最终用户节省大量数据计划成本。
网络网络,在<img>
标签中使用视频对于蜂窝连接的用户来说会好得多。
解码和视觉性能改进
接下来我们考虑一下微形式视频的解码和展示对浏览体验的影响。 H.264(和 H.265)具有硬件解码而不是使用主核心进行解码的显着优势。
我们如何衡量这一点?由于浏览器尚未实现建议的英雄图像 API,因此我们可以使用 Steve Souder 的用户计时和自定义指标策略作为图像开始向用户显示的时间的良好近似值。该策略不测量帧速率,但它确实大致告诉我们第一帧的显示时间。更好的是,我们还可以使用新采用的Image.decode()事件承诺来测量解码性能。在下面的测试页面中,我在<img>
标签中注入了 100 次独特的 GIF 和 MP4,并比较了解码和绘制性能。
ini
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); });
代码语言: JavaScript (javascript )
结果非常令人印象深刻!即使在我功能强大的 2017 MacBook Pro 上,在本地运行测试,没有网络限制,我也可以看到 GIF 绘制第一帧的时间比 MP4 长 20 倍(由事件指示onload
),解码时间也比 MP4 长 7 倍!
好奇?克隆存储库并自行测试。我要指出的是,在 GIF 与 MP4 的传输中添加网络条件会严重影响测试结果。具体来说:由于解码可以在最后一个字节完成之前开始发生,因此传输、显示和解码之间的增量变得更小。这真正告诉我们的是,仅节省字节就可以明显改善用户体验。然而,像我在本地主机运行中所做的那样分解网络,您可以看到使用视频对于能耗也具有明显的性能优势。
你如何实现这一点?
那么既然 Safari 技术预览版支持这种设计模式,那么您如何才能真正利用它,而不向不支持的浏览器提供损坏的图像呢?好消息!这相对容易。
- 选项 1:使用响应式图像
最简单的方法是使用<source type>
HTML5<picture>
标签的属性。
xml
<picture>
<source type="video/mp4" srcset="cats.mp4">
<source type="image/webp" srcset="cats.webp">
<img src="cats.gif">
</picture>
我想说我们可以就此打住。然而,Safari 中有一个令人讨厌的 WebKit 错误,它会导致预加载器无论 MIME 类型声明如何都下载第一个 <source>
。主 DOM 加载器意识到错误并选择正确的。然而,损害将会造成。预加载器浪费了提前下载图像的机会,最重要的是,开始下载错误的版本,浪费字节。好消息是我已经修复了这个错误,并且该补丁应该会出现在 Safari TP 45 中。
简而言之,在 Safari 的下一版本达到 Safari 总用户群的 90% 以上之前,不建议使用<picture>
和进行 MIME 类型选择。<source type>
- 选项 2:使用 MP4、动画 WebP 和回退到 GIF
如果您不想更改 HTML 标记,可以使用 HTTP 通过内容协商将 MP4 发送到 Safari。为此,您必须生成电影图片的多个副本(就像以前一样)以及Vary
基于Accept
和User-Agent
标题的响应。
一旦WebKit BUG 179178得到解决,这将变得更加清晰,并且您可以添加标头测试(与现在Accept: video/*
测试 的方式相同)。Accept: image/webp
但最终的结果是每个浏览器都获得了<img>
它支持的基于微形式视频的最佳格式:
浏览器 | 接受标头 | 回复 |
---|---|---|
游猎TP41+ | H.264 MP4 | |
接受:视频/mp4 | H.264 MP4 | |
铬42+ | 接受:图像/webp | 网页浏览器 |
歌剧 15 | 接受:图像/webp | 网页浏览器 |
接受:图像/apng | PNG | |
默认 | 动图 |
在 nginx 中,这看起来像:
ruby
if ($http_user_agent ~* "Safari/605[.0-9]+$") {
rewrite ^/(.*)$ https://www.domain2.com/$1 permanent;
}
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
告诉代理和 CDN 以不同的方式缓存每个响应。事实上,您可能应该将缓存控制标记为私有,并使用 TLS 来确保不太复杂的 ISP 性能增强代理不会缓存内容。
sql
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
代码语言: HTTP (http )
- 选项 3:使用 RESS 并回退到
如果您可以操作 HTML,则可以采用响应式服务器端 (RESS) 技术。此选项将浏览器检测逻辑移至 HTML 输出中。
例如,您可以使用 PHP 这样做:
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 }?>
代码语言: HTML、XML (xml )
如上所述,请务必发出响应Vary: User-Agent
,通知您的 CDN 有不同版本的 HTML 需要缓存。一些 CDN 会自动遵循Vary
标头,而其他 CDN 则可以通过简单更新 CDN 配置来支持这一点。
- 奖励:不要忘记删除音轨
现在,由于您不是将 GIF 转换为 MP4,而是将 MP4 转换为 GIF,因此我们还应该记住剥离音轨以节省额外的字节。 (请告诉我你没有使用 GIF 作为你的原件。对吗?!)音轨添加了额外的字节,我们可以快速删除这些字节,因为我们知道我们的视频无论如何都会静音播放。使用 ffmpeg 执行此操作的最简单方法是:
css
ffmpeg -i cats.mp4 -vcodec copy -an cats.mp4
有尺寸限制吗?
当我写这篇文章时,Safari 会盲目下载您在<img>
标签中指定的任何视频,无论它有多长。一方面,这是预期的,因为它有助于提高浏览器的性能。然而,如果您向用户推送 120 分钟的视频,这可能是致命的。我测试了多种尺寸,只要用户闲逛,所有尺寸都会被下载。所以,对你的用户要有礼貌。如果您想推送较长的视频内容,请使用该<video>
标签以获得更好的性能。
下一步是什么?响应式视频和英雄背景
现在我们可以通过<img>
标签交付 MP4,许多新用例的大门正在打开。我想到了两个:响应式视频和背景视频。现在我们可以将 MP4 放入srcset
s 中,使用客户端提示和 Content-DPR 改变我们对它们的响应,并使用艺术指导它们<picture media>
,好吧 -- 想想可能性!
ini
<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)
也可以!
arduino
<div style="width:800px, height: 200px, background-image:url(colin.mp4)"/>
结论
通过在标签中启用视频内容<img>
,Safari 技术预览版为令人惊叹的类似 GIF 的体验铺平了道路,而无需与 GIF 文件相关的可怕性能和质量成本。此功能对于用户、开发人员、设计人员和网络来说都非常棒。除了这一变化带来的巨大性能提升之外,它还开辟了媒体和电子商务企业多年来一直渴望实施的许多新用例。希望其他浏览器也能很快跟进。谷歌?微软?莫斯拉?三星?