基于官方规范系列篇之——HTML 篇(六)视频

336 阅读17分钟

大家好呀,我是前端创可贴。

上一章我们学习了关于源、跨域开放者策略、跨域嵌入策略、跨域隔离等相关内容,相信大家对于源和跨域有了更加深刻的了解。

这一章我们再一起来学习一下 HTML 中的视频。

视频

在这个视频横行其道的年代,大家对视频肯定都不陌生,大多视频平台不仅仅有移动端应用,还会有 Web 端,毕竟 Web 端不需要预先下载平台即可直接访问并观看。相信有许多人像创可贴我一样,在 PC 端看视频不喜欢下载应用,而是使用 Web 端观看。

在页面中,我们通过 video 元素即可嵌入视频,video 元素可以用于播放视频或带有字幕的音频文件,没想到吧,音频竟然也可以用 video 元素,其主要是为了给音频文件加字幕,加字幕这个功能我们下面小节再细说。

<video src="xxx.mp4"></video>

一些旧版本浏览器,或者在浏览器设置里关闭了网站的视频功能,则浏览器不支持播放视频,所以为了兼容性,我们一般在嵌入视频时会做一个兜底的展示,例如当浏览器不支持视频时展示一段提示信息,当然了如果浏览器支持播放视频是不会展示提示信息的。通过在 video 元素内放置内容即可:

<video src="xxx.mp4">
  您的浏览器不支持播放视频
</video>

controls

指定了该属性,浏览器会显示默认的播放工具,可以暂停/开始播放、调节音量、全屏、打开字幕等。

<video src="xxx.mp4" controls></video>

如果没有该属性,浏览器不会显示任何的播放工具,甚至没有播放按钮。这是方便我们开发者可以自定义播放工具,用来控制视频的播放等。

我们常看的视频网站,都会关闭 controls,并且自定义播放工具,我们来看看 B 站:

可以看到,B 站的播放工具都是自定义的 DOM 来展示的。

poster

如果视频加载时间很久,视频元素就会黑屏很久,体验不是很好,所以可以让视频元素在加载视频的过程中,先显示一张相关的图片,缓解用户焦躁的心情。通过 poster 属性指定图片的 url:

<video src="xxx.mp4" controls poster="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png">
  您的浏览器不支持播放视频
</video>

poster 属性设置生效后,会产生一个 poster 帧(poster frame),poster 帧就是 poster 属性设置的那张图片。

默认情况下,视频还没播放之前,视频元素的宽高,是 poster 属性中图片的宽高,而一旦视频开始播放,视频元素的宽高就会变为视频的原始尺寸,可能会触发回流重绘。可以将 poster 属性图片尺寸设置为视频的尺寸大小,或者将 video 元素设置固定的宽高等。

poster 属性带来的缺点是多请求了一张图片,理所当然的也会推迟 window 对象的 load 事件的触发。

crossorigin

crossorigin 属性告诉浏览器怎么处理跨域资源,是否要携带资源凭证。该属性不仅可以用在 video 属性上,还可以用在 audioimglinkscript 元素上。该属性与上一章我们学习的跨域有很大的关系。

它的值可以是:

  • anonymous跨域资源不会携带 cookie,响应头的 Set-Cookie 也不会生效,并且如果资源没有设置 CORS 相关响应头,资源会获取失败
  • use-credentials跨域资源会携带 cookie同样的如果资源没有设置 CORS 相关响应头,资源会获取失败
  • "" 无效值或者省略:效果同 anonymous。

在测试之前先看看我们的视频资源是携带了 cookie 的:

当我们设置 crossorigin 值为 anonymous 后:

<video
  src="xxx.mp4"
  controls
  poster="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"
  crossorigin="anonymous"
></video>

可以看到,请求不会携带 cookie,并且视频资源和图片都没有设置 CORS 相关响应头,所以会获取失败。

而设置为 use-credentials 后:

<video
  src="xxx.mp4"
  controls
  poster="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"
  crossorigin="use-credentials"
></video>

可以看到,请求会携带 cookie,并且同样的,视频资源和图片都没有设置 CORS 相关响应头,所以会获取失败。

loop

loop 属性用于设置视频循环播放,即视频播放到结尾后浏览器会自动重新将其从头开始播放。

<video src="xxx.mp4" controls poster="yyy.png" loop>
  您的浏览器不支持播放视频
</video>

muted

muted 属性用于设置视频是否静音,静音的视频是可以自动播放成功的,不会被浏览器的自动播放拦截策略给拦截,后面会详细说明自动播放相关内容。

<video src="xxx.mp4" controls poster="yyy.png" loop muted>
  您的浏览器不支持播放视频
</video>

preload

preload 属性用于告诉浏览器在视频播放之前哪些内容要先预加载,以提供更好的用户体验。

值可以是:

  • none:视频不需要预加载。
  • metadata:只需要预加载视频的元信息(例如视频大小等)。
  • auto:整个视频文件都可以加载,即使用户不会用到它。
  • "" :等同于 auto

不同的浏览器,该属性的默认值也不同,规范建议默认值为 metadata。

autoplay 属性优先级比 preload 属性高,设置了 autoplay 就需要加载整个视频文件,忽略 preload 的值。

videoWidth 和 videoHeight

video.videoWidthvideo.videoHeight 属性返回视频的原始宽度和高度,单位为 CSS 像素,如果视频的尺寸未知,则返回 0。

如果给 video 元素设置了不同于视频本身的宽高,videoWidth 和 videoHeight 仍然返回视频本身的自然宽度和高度。

视频格式与编解码器

视频有很多种文件格式,例如我们常见的 MP4WebM 等格式。在具体介绍这些格式以及编解码器之前,我们先考虑一个问题,为啥会有这么多的视频格式和编解码器呢?

主要是因为视频技术在不断发展,同时需要在不同应用场景下权衡质量、文件大小、设备兼容性和计算资源消耗等多方面的需求,这导致了许多不同的视频编码格式的出现和应用。

原因大致可以归类为这么几点:

  • 技术进步和效率提升:视频压缩的目标是尽可能减少数据量,同时尽量保留原始质量。于是随着技术的发展,新的编码格式一般都比旧的格式更高效。并且视频分辨率从 SD(标清)到 HD(高清)、4K、8K,不断提升,旧的编码格式可能不支持高分辨率或效率低。
  • 兼容性与设备限制:早期的设备可能只支持老旧的编码格式(如 MPEG-2)。新设备(如智能手机、电视)会逐渐支持新的格式(如 AV1、VP9)。
  • 行业标准与专利:一些格式成为行业标准(如 H.264 和 H.265),被广泛应用于流媒体、蓝光光盘等领域。以及像 WebM(VP8、VP9)和 AV1 等开源格式无版权费用,更适合互联网应用。
  • 不同的应用场景需求:不同的场景会有不同的侧重点,例如流媒体与实时播放需要高度压缩、快速解码,以减少网络带宽消耗和加载时间(如 H.264、VP9)

有这么多的文件格式,不同的浏览器可能有不同的支持范围,对于不支持的视频格式,浏览器就会无法播放,那么我们该怎么解决这个问题呢?

我们可以通过 source 元素指定多个视频文件格式,浏览器会使用这一堆中第一个它支持的格式。

<video controls>
  <source src="myVideo.webm" type="video/webm" />
  <source src="myVideo.mp4" type="video/mp4" />
  <p>
    您的浏览器不支持播放视频,
    <a href="myVideo.mp4" download="myVideo.mp4">点击</a>下载
  </p>
</video>

为 source 元素指定 type 属性,可以让浏览器直接判断是否是它支持的类型,不再需要从服务器获取资源以后才判断。

常见视频格式

格式常见容器常见编解码器特性浏览器支持
MP4(MPEG-4,Moving Picture Experts Group 4).mp4H.264, H.265 (HEVC), AAC高压缩比,兼容性好,支持多种主流编解码器广泛支持,包括移动设备
WebM(Web Media).webmVP8, VP9, Opus开源,针对网页优化,支持透明背景Chrome, Firefox, Edge 等现代浏览器
OGG(Ogg).ogvTheora, Vorbis开源,但压缩率较低Firefox, Chrome, Opera
AVI(Audio Video Interleave).avi多种(较老,H.264等)兼容性较低,文件大不推荐用于网页
MOV(Apple QuickTime movie).movH.264, AAC苹果设备支持好仅部分浏览器支持
MKV(Matroska Video).mkvVP9, H.264, AAC高质量支持,但兼容性差现代浏览器有限支持
FLV(Flash Video).flvH.264针对 Flash,已过时需要 Flash 支持,不推荐

常见编解码器

编码器简称特性支持的容器
AV1(AOMedia Video 1)下一代免费开源编码;更高效的压缩(比 VP9/H.265 高 30%);适合 8K 视频;MP4, WebM
AVC (H.264)(Advanced Video Coding)高效压缩,支持 720p、1080p、4K;广泛用于流媒体、视频会议、蓝光等;3GP, MP4
HEVC (H.265)(High Efficiency Video Coding)更高效的压缩(比 H.264 高 50%);支持 4K、8K 视频;MP4
MP4V-ES(MPEG-4 Video Elemental Stream)广泛用于早期设备,但在现代设备中逐渐被 H.264 和其他高效编码标准取代;3GP, MP4
MPEG-1(MPEG-1 Part 2 Visual)广泛支持于 VCD 播放器、老式 DVD 播放器和部分嵌入式系统中;MPEG, QuickTime
MPEG-2(MPEG-2 Part 2 Visual)早期的标准,用于 DVD、数字电视等;MP4, MPEG, QuickTime
Theora(Theora)免费开源编码,早期与 VP8 竞争;Ogg
VP8(Video Processor 8)开源,专为网络视频优化;3GP, Ogg, WebM
VP9(Video Processor 9)更高效的压缩(比 VP8 提高 50%);主要用于 YouTube、WebRTC 等;MP4, Ogg, WebM

事件

罗列一下视频中常用的一些事件:

事件名触发时机
canplay浏览器已经加载了足够的数据,可以播放视频了。但是视频数据可能还没有加载完,可能还需要进一步缓冲数据。
canplaythrough浏览器估算已缓冲的数据足够支持视频从头到尾无中断播放时触发。
durationchange视频的 duration 属性变化时触发,也就是视频的总时长发生变化,例如视频的元数据加载完成
ended视频播放完毕
error获取视频数据发生错误,或者不支持资源格式
loadeddata视频的第一帧加载完成
loadedmetadata视频的元数据加载完成,例如视频总时长、宽高度等信息
loadstart浏览器开始加载视频资源
pause视频暂停
play视频播放
volumechange音量变化

演示一下 error 事件。视频可能会因为各种原因导致播放失败,我们可以捕获它们的错误,并且可以根据错误的类型进行对应的提示。

<video src="xxx.mp4" controls onerror="failed(event)"></video>

<script>
 function failed(e) {
   switch (e.target.error.code) {
     case e.target.error.MEDIA_ERR_ABORTED:
       alert('终止了视频播放');
       break;
     case e.target.error.MEDIA_ERR_NETWORK:
       alert('网络错误');
       break;
     case e.target.error.MEDIA_ERR_DECODE:
       alert('出现了损坏问题或者浏览器不支持视频用到的特性');
       break;
     case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
       alert('服务器或网络错误,或者格式不支持');
       break;
     default:
       alert('未知错误');
       break;
   }
 }
</script>

自动播放

通过 autoplay 布尔属性设置为 true,可以设置视频在加载完后自动播放,无需用户点击。

<video src="xxx.mp4" poster="yyy.png" autoplay>
  您的浏览器不支持播放视频
</video>

也可以在视频加载完后通过 JavaScript 代码让其播放,达到自动播放的效果:

const video = document.querySelector('video');

video.addEventListener('loadeddata', () => {
  video.play();
});

但是一些浏览器允许用户禁用自动播放,以避免音频或视频在未经许可的情况下自动播放,这样可以防止用户体验被突兀的声音或视频打扰。所以,我们不能完全依赖自动播放功能来确保内容的播放。我们可以通过监听 video 元素的 play 事件来确认视频是否成功播放。

const video = document.querySelector('video');

video.addEventListener('play', () => {
  console.log('视频正常播放');
  // 执行在视频播放时触发的逻辑
});

自动播放失败

大家需要注意一点,其实音视频的自动播放,特别是当它们是有声音的时候,可能会让用户感到不愉快,设想一下你正在聚精会神的浏览一个网站,它突然自动播放了一段声音很响,或者内容较为恐怖的音频,你会不会想给网站管理员寄点土特产?

而且,自动播放会在后台消耗流量,尤其在移动端设备上,用户一般希望能自己控制流量的消耗以节省流量。

所以大家尽量不要开启音视频的自动播放,而是让用户自己选择是否播放。但是也不是说自动播放这个功能就是禁忌,有些场景和需求就是需要音视频的自动播放。

而浏览器在默认情况下会拦截有声音的音视频的自动播放,也就是浏览器的自动播放拦截策略(Autoplay Blocking Policy)

当满足以下条件之一时,就会满足自动播放拦截策略的自动播放条件:

  • 音视频本身是静音的,或者音量调为静音
  • 用户与网站产生过交互(例如点击鼠标、按下键盘等)
  • 浏览器将网站加入了自动播放白名单
    • 自动允许:如果浏览器检测到用户在该网站上频繁与媒体内容互动,例如经常点击播放视频,浏览器可能会自动将该网站加入自动播放白名单;
    • 手动允许:用户也可以通过浏览器的设置或其他界面手动将网站加入白名单。
  • 设置了 Permissions-Policy 响应头的 autoplay 权限(试了一下没有用,给 HTML 的响应头加了 Permissions-Policy 为 autoplay=(*),以及 iframe 设置 allow="autoplay",并不会自动播放,如果有成功的小伙伴还请指教一下)

只要满足以上条件之一,就可以让音视频自动播放,不会被拦截。

字幕

大家平时在看电影的时候,一般都会看到电影里面含有字幕,字幕功能可以大大提高观影体验。没错,我们 HTML 的视频也可以自定义添加字幕。

给视频内容添加字幕,有 2 种方式:

  • 通过加载后缀名为 .vtt 的资源文件;
  • 通过 WebVTT API

.vtt 文件

WebVTT(Web Video Text Tracks) 文件,用于给 Web 视频添加自定义字幕,内容只需要遵循着简单的格式,就可以通过 track 元素加载该文件并且为视频添加字幕。

我们先来看看一个有效的 vtt 文件内容长什么样子:

WEBVTT

00:00.000 --> 00:00.900
你瞅啥

00:01.000 --> 00:01.400
瞅你咋的

00:01.500 --> 00:02.900
再瞅一个试试

00:03.000 --> 00:04.200
试试就试试

格式很简单,第一行标注 WEBVTT,然后跟着每一段字幕的起始与终止时间,以及字幕的内容。

然后就可以通过 track 元素的 src 属性加载它:

<video controls src="video.webm">
  <track default kind="captions" src="captions.vtt" srclang="中文" />
</video>

track 元素

track 元素还有一些属性,可以设置字幕相关信息:

  • kind 属性:指定字幕的类型是什么,值可以是
    • subtitles :语言的翻译,例如英文电影中的中文字幕。也可以包含关于视频的一些背景信息,例如电影中常见的时间、地点信息。
    • captions :音频的翻译,例如中文电影中的中文字幕。可能包含一些非语言相关的信息,例如背景音乐。适用于听力障碍或者静音的场景。
    • chapters :提供视频的导航信息,方便用户跳转到相关内容。
    • metadata :脚本相关,对用户不可见。
  • src 属性:vtt 文件的 URL,并且必须与当前的文档同源,除非 video 元素设置了 crossorigin 属性。
  • srclang 属性:指定字幕的语言类型。当 kind 属性值为 subtitles 时,该属性必须要设置。当 video 元素有多个 track 元素并且设置了 srclang 属性,可以在视频的工具栏里看到设置的多个语言类型的字幕选项以供选择。
  • default 属性:设置当前字幕为默认字幕,浏览器会默认启用当前字幕。每个 video 元素只能设置一个 track 元素的 default 属性。

通过指定多个包含 kind 和 srclang 属性的 track 元素时,就会有多个语言类型的字幕供用户选择:

<video controls src="video.webm">
  <track default kind="captions" src="captions.vtt" srclang="中文" />
  <track kind="subtitles" src="captions.vtt" srclang="英文" />
  <track kind="subtitles" src="captions.vtt" srclang="日文" />
  <track kind="subtitles" src="captions.vtt" srclang="韩文" />
</video>

WebVTT API

通过 HTMLMediaElement.addTextTrack() 即可为视频添加一种语言类型的字幕,其类似于一个 track 元素。

再将 addTextTrack() 方法的返回值调用 addCue 方法,添加字幕的每一部分,也就是每一段字幕的起始与终止时间,以及字幕的内容。

const video = document.querySelector("video");
const track = video.addTextTrack("captions", "中文");
track.mode = "showing";
track.addCue(new VTTCue(0, 0.9, "你瞅啥"));
track.addCue(new VTTCue(1, 1.4, "瞅你咋的"));
track.addCue(new VTTCue(1.5, 2.9, "再瞅一个试试"));
track.addCue(new VTTCue(3, 4.2, "试试就试试"));

虽然 HTML 原生带有字幕功能,但是大部分的视频平台例如 B 站、Youtube 等添加的字幕并不是用原生的字幕功能,而是通过自定义的 DOM 添加的,兼容性强并且更加好控制,可以实现更加丰富的功能和样式等。

为字幕设置样式

我们还可以为自定义的字幕添加样式,毕竟默认的样式还是比较难看的,对于我们追求美的前端工程师们来说,这是不可容忍的。

通过 ::cue 伪元素可以给字幕添加样式,它会匹配上所有的字幕元素。字幕元素的功能是受限的,所以字幕元素的样式只能设置以下 CSS 属性:

  • color
  • opacity
  • visibility
  • text-decoration
  • text-shadow
  • background
  • outline
  • font
  • line-height
  • white-space

例如给字幕元素修改颜色:

<head>
  <style>
    ::cue {
      color: red;
    }
  </style>
</head>
<body>
  <h1>前端创可贴</h1>

  <video src="xxx.mp4">
    <track default kind="captions" src="./subtitle.vtt" srclang="zh" />
  </video>
</body>

可以看见,样式生效了,但是上面列举的字幕元素可以应用的 CSS 样式,只有寥寥几个,所以原生字幕功能可以实现的功能非常有限,所以这也是为什么大部分视频网站都选择自定义 DOM 实现的原因之一。

我们还可以在 vtt 文件里添加一些标识,在编写 CSS 的时候可以针对特定的标识添加样式:

WEBVTT

00:00.000 --> 00:00.900
<b>你瞅啥</b>

00:01.000 --> 00:01.400
<c.myclass>瞅你咋的</c>

00:01.500 --> 00:02.900
<lang zh-CN>再瞅一个试试</lang>

00:03.000 --> 00:04.200
试试就试试
<style>
  ::cue {
    color: red;
  }
  ::cue(b) {
    color: blue;
  }
  ::cue(.myclass) {
    color: aqua;
  }
  ::cue([lang="zh-CN"]) {
    color: bisque;
  }
</style>

结束语

这一章我们学习了视频的相关内容,我们学习了很多的相关属性,例如 controls、poster、crossorigin 等,这些属性使用率都比较高,也非常有用,大家一定要掌握。

又学习了视频的生命周期中会触发的一些常用的事件,在我们需要进行一些特定时期的监听时,这些事件会非常有用。

还学习了关于视频自动播放失败的场景以及解决方案,可以看到浏览器为了提高用户的浏览体验,限制了很多开发者的行为。

最后又介绍了如何设置字幕以及修改样式,虽然大部分视频网站并不会选择用原生的字幕功能,但是我们还是要了解一下原生的功能,才能知道为什么视频网站要选择自定义 DOM 而不是原生功能。

那么这一章的介绍就结束了,咱们下一章再见啦。

欢迎关注我的公众号,前端创可贴。