【译】iOS 上 video 标签的 的一些限制
原文地址: https://webkit.org/blog/6784/new-video-policies-for-ios/
如果接触过 ios 上的开发,在iphoneOS 3 的时候 safari 只允许用户与 video 进行交互的时候才会触发数据的加载。但是为了将更多的媒体播放控制权重新回到网页开发者,iOS 8放宽了这一限制:Safari开始支持 preload="metadata"
属性,允许<video>
和<audio>
元素加载足够的媒体数据,以确定媒体的大小,持续时间和可用的轨迹。对于iOS 10中的 Safari,进一步放宽了对静音<video>
元素的用户手势要求。
缘由
事实证明,人们很喜欢GIF。但与现代视频编解码器(如H.264)相比,GIF格式的编码方式与编码动画图像非常不具有性价比。我们发现,GIF的带宽可以高达十二倍。这是非常昂贵的,许多最大的 GIF 提供商已经从GIF转向 <video>
元素。由于这些GIF大部分作为视频片段开始生活,被转换为GIF。如今我们需要直接播放这些片段。
但是,虽然这一举措可以节省网站的带宽成本以及节省用户的电池。但是你还需要付出一些成本。在iOS 9上,<video>
只会由于用户手势触发而开始播放。那么,页面将有一个<img>
替换<video>
从而将引导用户进行触发,并且,在iPhone上,在 <video>
开始播放时,会进入全屏模式。
关于用户手势要求的注意事项:当我们说一个操作必须发生“作为用户手势结果”时 去调用JavaScript 。例如:video.play()
必须当用户触发了 touchend
,click
,doubleclick
,或keydown
事件。所以,
button.addEventListener('click', () => {
video.play();
})
而
video.addEventListener('canplaythrough', () => {
video.play();
})
则不不会触发播放。
类似地,网络开发人员通过将<video>
元素集成到其页面的中来做一些非常惊艳的效果。并且由于没有用户手势要求,这些页面在iOS上根本不起作用,或者<video>
元素作为动画全屏背景的话,这些都是没有效果的。
WebKit的新的策略
从iOS 10开始,WebKit放宽其内置和自动播放策略,使某些效果得以实现,但是你还是需要考虑用户的流量和电量消耗。
默认情况下,WebKit将具有以下策略:
<video autoplay>
元素现在 autoplay 符合下列条件情况能够触发:
-
<video>autoplay
如果它们的源媒体不包含音频轨道,则元素将被允许没有用户手势的情况下播放。 -
<video muted>
设置静音的时候也允许自动播放 -
如果某个
<video>
元素获得音轨或在没有用户手势的情况下不是静音,播放将暂停。 -
<video autoplay>
元素只能在屏幕上可见时开始播放,例如当它们滚动到视口中时,通过CSS可见,并插入到DOM中。 -
<video autoplay>
如果元素变得不可见,例如通过从视口滚动出来,元素将会暂停。
<video>
元素现在可以实现play()需要满足以下条件的元素:
-
<video> play()
如果它们的源媒体不包含音轨,或者如果它们的muted属性被设置,则元素将被允许不触发手势就能播放。 -
如果某个
<video>
元素获得音轨或在没有用户手势的情况下变得未静音,播放将暂停。 -
<video>
元素允许play()
,当它在屏幕上不可见或出现在视口之外时。 -
video.play()
将返回 Promise,如果不满足任何这些条件,将被拒绝。 -
在iPhone上,
<video playsinline>
元素现在可以在线播放,并且播放开始时不会自动进入全屏模式。 -
<video>
没有playsinline
属性的元素将继续全屏模式以播放。 -
当使用 手势 退出全屏时,
<video>
元素不会playsinline
继续播放。
对于iOS上的WebKit框架的客户端,仍然可以通过API控制这些策略,从而满足自己具体的需求。有关自动播放策略的更细粒度控制,请参阅新的WKWebViewConfiguration
属性mediaTypesRequiringUserActionForPlayback
。iOS 10上的Safari将使用WebKit的默认策略。
关于playsinline属性的注释:此属性最近已被添加到HTML规范中,而WebKit已经通过取消其旧webkit-playsinline属性来修改该属性。自从iPhoneOS 4.0以来,这种属性得到了支持,并且根据我们更新的未经修订的策略,我们很高兴能够进行未修改webkit-playsinline。不幸的是,这一变化并在iOS 10 Developer Seed 2成为截止。如果您想使用iOS Developer Seed 2来实验这项新政策,则前缀属性将会起作用,但是我们鼓励您转换到未定义的属性,直到未来可用。
example
作为开发者我们如何利用这些新政策呢?假设有一个博客文章或者有许多GIF的文章,那么它们更喜欢用作<video>
元素。以下是简单GIF替换的示例:
<video autoplay loop muted playsinline>
<source src="image.mp4">
<source src="image.webm" onerror="fallback(parentNode)">
<img src="image.gif">
</video>
function fallback(video)
{
var img = video.querySelector('img');
if (img)
video.parentNode.replaceChild(img, video);
}
在iOS 10上,如果没有任何一个<video>
的源不被支持,则可以提供Gif来进行播放。
如果您的页面设计需要不同的行为,允许内联播放,而在需要全屏播放时,请使用-webkit-video-playable-inline媒体查询来区分两者:
<div id="either-gif-or-video">
<video src="image.mp4" autoplay loop muted playsinline></video>
<img src="image.gif">
</div>
#either-gif-or-video video { display: none; }
@media (-webkit-video-playable-inline) {
#either-gif-or-video img { display: none; }
#either-gif-or-video video { display: initial; }
}
这些新政策意味着元素的更高级的使用成为可能,例如画使用 <canvas>
绘制 <video>
。
var video;
var canvas;
function startPlayback()
{
if (!video) {
video = document.createElement('video');
video.src = 'image.mp4';
video.loop = true;
video.addEventListener('playing', paintVideo);
}
video.play();
}
function paintVideo()
{
if (!canvas) {
canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
document.body.appendChild(canvas);
}
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
if (!video.paused)
requestAnimationFrame(paintVideo);
}
<button onclick="startPlayback()">Start Playback</button>
相同的方法可以用于渲染为WebGL。注意,在这个例子中,用户的手势(click事件)是必需的,因为<video>
元素不在DOM中,因此不可见。一个<video style="display:none">
或者<video style="visibility:hidden">
也是一样。
这些新政策真的使视频成为提升我们网站的交互和设计,而不会对降低用户的宽带和电量消。有关更多信息,请联系 @jernoble ,AppleWorks Web技术传播者Jonathan Davis,@ jonathandavis 或者 @WebKit。