隐藏全屏模式下的原生 HTML5 视频控件

Avatar of Sara Soueidan
Sara Soueidan 发布

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费额度!

以下是 Sara Soueidan 的客座文章。 我通过她在 CodePen 上的所有出色作品认识了 Sara。 她正在开发一些自定义的 HTML5 视频控件,并注意到当视频进入全屏模式时,自定义内容会丢失(示例)。 通过深入研究 Shadow DOM,Sara 找到了一个解决方案……

如果您曾经使用过 HTML5 视频,那么您可能想知道,当您只向 DOM 添加了一个 <video> 标签时,页面上是如何出现一堆控制按钮、滑块和滑块滑块的。

这些控制元素是从哪里来的?

浏览器将这些控件作为视频标签的“子树”添加到文档的渲染中。 这些元素(按钮、滑块等) DOM 的一部分,但您实际上无法在主 DOM 树中看到它们,您只能看到它们渲染到页面上。 稍后将详细介绍。

全屏模式下 HTML5 视频控件的问题

最近在开发一个自定义 HTML5 视频框架时,我遇到了很多设计师和开发人员在这个领域遇到的一个问题。 当视频进入全屏模式时,它会显示浏览器的原生控件,而不是我正在开发的自定义控件。 和许多其他人一样,我四处寻找这个问题的答案,但没有找到任何有用的信息。(更新:此错误已在 Chrome 错误跟踪器中提交)。

经过一些检查,我发现

  1. 原生控件仍然存在。 通过将视频元素的 controls 属性设置为 false,我们可以隐藏控件,但出于某种原因,在进入全屏模式时,它们会重新出现,尽管在普通屏幕模式下它们是隐藏的。(为什么?)
  2. 自定义控件在全屏模式下隐藏在视频下方。 使用开发工具检查控件显示,控件隐藏在下方的原因是,用户代理的样式表(在本例中为 Chrome 的样式表)正在覆盖应用于控件的样式,并且使用了非常奇怪的 z-index 值,我必须说!
Chrome 的用户代理样式表应用的高 z-index

我们如何才能使其正常工作? 我们如何防止原生控件在全屏模式下出现,而是显示我们自己的自定义样式控件?

第二点很容易:只需覆盖用户代理样式表即可。 我们一直在样式表中这样做。 我们很快就会讲到这一点。 但是第一点呢? 我们如何隐藏浏览器添加但我们在使用的 DOM 树中看不到的元素?

请注意,本文中解释的隐藏原生控件的技术仅适用于支持 Shadow DOM 的浏览器

快速了解 Shadow DOM

浏览器生成的 DOM 元素子树就是我们所说的“Shadow DOM”。 简单来说,它是一堆 DOM 元素,与您已经熟悉的元素(如 <div><span>)相同,它们由浏览器作为文档片段添加,并像主 DOM 树一样渲染到页面上。

James Edwards 在他为 SitePoint 撰写的一篇文章中完美地总结了 Shadow DOM 的功能

Shadow DOM 通过创建文档片段来封装内容。 有效地,Shadow DOM 的内容是一个不同的文档,它与主文档合并以创建最终的渲染输出。

事实上,一些浏览器已经使用它来渲染一些原生部件。

浏览器这样做的原因是,浏览器开发人员决定封装一些 DOM 元素以将其隐藏在我们开发人员面前,这样我们就不用担心这些元素的实现细节,从而试图使我们更容易使用。 此外,正如 James Edwards 在他的文章中所说

由于它是隔离的,用户无法意外地破坏它,也不可能与您使用的任何类或 ID 发生命名冲突,并且主页面上的 CSS 根本不会影响它。

所以我们现在知道,添加到视频标签的控件只是浏览器为此标签生成的 Shadow DOM 子树的一部分。

隐藏原生视频控件

我们需要能够为 Shadow DOM 中的控件设置样式,但是如果我们知道的常规 CSS 选择器无法访问 Shadow DOM 元素,我们该怎么做呢?

在阅读了 Dimitri Glazkov 撰写的这篇精彩的介绍文章后,我了解到“有一个方便的伪属性功能,它允许 Shadow DOM 子树将任意伪元素标识符与子树中的元素关联起来。”

这意味着可以通过其关联的伪元素来定位 Shadow DOM 子树中的一些元素,从而为其设置样式。 这听起来很棒!

但是我们如何确定与我们需要设置样式的 Shadow DOM 元素关联的伪元素是什么呢? 一些元素或多或少是已知的,例如范围输入,它有一个可用于在 WebKit 浏览器中为其滑块设置样式的伪元素

::-webkit-slider-thumb

Firefox 还提供了两个伪元素来设置范围输入的样式,因为它从版本 23.0 开始支持它们

::-moz-range-track

::-moz-range-thumb

但是其他不太为人知的与其他 Shadow DOM 元素关联的伪元素呢? 与它们关联的伪元素是什么? 要找出答案,Chrome 开发工具可以帮上忙!

确定与 Shadow DOM 元素关联的伪元素

Chrome 开发工具的一项很棒的功能是,您可以在“元素”面板中检查 Shadow DOM 子树,就像检查“常规”DOM 树一样。 您只需启用此功能即可

  1. 转到开发工具设置(单击开发工具右下角的小齿轮图标)
  2. 在“常规”选项卡中,选中“显示 Shadow DOM”选项
  3. 重新启动开发工具(关闭并重新打开)

现在,当您检查 <video> 元素时,您会看到类似于以下屏幕截图的内容

使用 Chrome 开发工具检查添加到 <video> 元素的 Shadow DOM 子树会显示一个新的 #document-fragment

然后,就像您可以获取任何 HTML 元素的样式规则(如果在“元素”面板中单击它),您也可以看到与 Shadow DOM 的子树关联的伪元素。 非常棒,对吧? :)

Chrome 开发工具中的“CSS”面板显示了与 Shadow DOM 子树内的 <div> 关联的伪元素名称

因此,对于视频控件,我们可以从屏幕截图中看到,有一个名为 ::-webkit-media-controls 的伪元素,顾名思义,它与包含媒体控件的标签关联。

在该伪元素上设置 display:none !important; 会在普通和全屏模式下完全隐藏该元素。

::-webkit-media-controls {
  display:none !important;
}

但请记住,此伪元素与子树中最外层的 <div> 关联,该 <div> 将包含媒体控件,所有类型的媒体控件,这意味着如果您在页面上的某个位置有一个 <audio> 标签,您也将隐藏该媒体元素的控件。

因此,除非您要隐藏所有浏览器原生媒体控件,否则您需要指定要隐藏的媒体控件类型,即与视频元素关联的那些控件,并且您可以通过指定此伪元素的“范围”来定位它们

video::-webkit-media-controls {
  display:none !important;
}

这将完全隐藏原生控件。

另一种选择是,您可以深入子树以查找与包含实际控件(按钮、滑块等)的内部和更具体的 div 关联的伪元素,并将其隐藏。

因此,深入一层,我们得到了与内部 div 关联的伪元素

video::-webkit-media-controls-enclosure {
  display:none !important;
}

将此伪元素的 display 属性设置为 none 将完全隐藏原生控件,无论是在普通模式还是全屏模式下。 您还可以看到,此伪元素在范围(视频元素)和与其关联的 div 方面更具体:包含实际控件元素的 div

这几乎就是隐藏全屏模式下原生控件所需做的全部操作。 很简单,对吧?

显示自定义视频控件

至于自定义控件,在隐藏原生控件后,它们仍然没有出现在我的演示中,因为,正如你在上面的屏幕截图中看到的,用户代理样式表为全屏模式设置了 z-index 值。

Chrome 的用户代理样式表应用了较高的 z-index 值。

我不知道开发人员为什么选择这个特定的值,但可能是因为,正如 Nate Volker 在他下面的评论中指出的那样,这个数字是 32 位有符号整数的最大值,这可能是浏览器开发人员用来表示 z-index 值的数据类型。因此,为了确保自定义控件可见,您需要**将自定义控件的 z-index 设置为等于或高于此值**。

将其设置为 2147483646 会导致控件在 Firefox 的全屏模式下消失,有时(一个 bug?),也会在 Chrome 中消失,因此控件容器的 z-index 应 >= 2147483647。

.custom-video-controls {
  z-index: 2147483647;
}

总结

为了在支持 Shadow DOM 的浏览器中隐藏全屏模式下的原生控件,您需要

  1. 定位与之关联的伪元素:video::-webkit-media-controls-enclosure,您可以使用 Chrome 的开发者工具并检查 Shadow DOM 来找到它,并将其 display 设置为 none,然后显示您自定义样式的控件。
  2. 将自定义控件的 z-index 设置为高于用户代理样式表提供的 z-index 的值。

就是这样!

演示

查看 Chris Coyier 在 CodePen 上的笔 Custom HTML5 Video Controls in Full Screen@chriscoyier)。

不支持 Shadow DOM 的其他浏览器呢?

在工作过程中,我还测试了 Firefox 中的结果。将z-index设置为上面提到的值也会使自定义控件出现在 Firefox 的全屏模式中,因此显示控件很容易,但 Shadow DOM 解决方案不起作用,因为 Firefox 尚未支持它,因此原生控件在全屏模式下仍然出现。

当然,您可以在其他不支持 Shadow DOM 的浏览器中期待类似的行为。

我发现隐藏这些浏览器中原生控件的唯一方法是使用自定义控件覆盖原生控件,方法是简单地使用针对全屏模式的基本 CSS 样式将自定义控件定位在其顶部。
这会隐藏原生控件,但也存在一个限制:自定义控件不能具有透明背景,否则原生控件将显示出来。

这里还有另一种可能的解决方案。James Edwards 先生在他的下面的评论中指出,原生控件也可以通过另一种方式隐藏在全屏模式下,而无需使用 Shadow DOM,方法是将全屏模式应用于一个元素,例如,一个

,包含视频元素。我测试了他的技术,它在 Chrome 中有效,在 Windows 7 上最新版本的 Firefox 中也有效,并且根据 James Edwards 的说法,它也应该在其他支持全屏模式的浏览器中有效。

进一步阅读

如果您有兴趣,还可以了解如何使用 Shadow DOM API 和 HTML <template> 创建您自己的“封装”代码和 HTML 模板,请观看 Peter Gasston 关于 Web Components 的此演示,他在今年的 CSSConfEU 上发表了该演示。