这是一篇由 Markus Stange 撰写的客座文章。Markus 通常负责 Firefox Mac 主题的实现,但这次他进行了一次在 Gecko 布局引擎中的小侧游,以实现 -moz-element
。
在 Firefox Beta 4 中,我们为 CSS background-image
属性引入了新的扩展:能够使用 -moz-element(#elementID)
将任意元素作为背景绘制。
This element will be used as a background.
This box uses #myBackground1 as its background!
-moz-element()
图像的工作方式与普通的 url()
图像相同。这意味着它受所有熟悉的背景属性的影响,例如 background-position
、background-repeat
,甚至 background-size
。
例如,使用 background-size
可以创建所引用元素的缩略图
#thumbnails li {
width: 160px;
height: 120px;
background-repeat: no-repeat;
background-size: contain;
}
关于 -moz-element
,需要注意三点
-
它是实时的:无论何时在引用元素中发生任何事情,
-moz-element
背景图像都将更新。它还会显示诸如文本选择或闪烁的光标之类的内容。 -
它是纯视觉的。这意味着您无法“点击”到原始元素。这是设计使然。
-
它适用于任何 HTML 元素。甚至包括
<iframe>
……
<video>
…… 和
<canvas>
。
事实上,将画布用作背景在某些应用程序中很有用。例如,如果您正在 在浏览器中将褐色调应用于 CSS 背景图像,则现在不再需要将处理后的画布图像 转换为数据 URI。相反,您可以直接将画布本身设置为背景图像。
使用画布作为背景图像也 受 Webkit 支持,使用 -webkit-canvas()
。
绘制循环
关于递归引用的简要说明:如果您尝试 绘制一个已经通过 -moz-element
绘制的元素,则会检测到绘制循环并阻止它。因此,您需要考虑其他方法来绘制您的 谢尔宾斯基地毯。
隐藏引用的元素
有时您不希望原始引用元素可见,而只希望 -moz-element
背景图像可见。那么您该怎么做呢?您不能只是在元素上设置 display: none
或 visibility: hidden
,因为那样的话,-moz-element
背景图像中也没有任何内容可以绘制——它将是透明的。
相反,您需要阻止元素在屏幕上呈现而不真正隐藏它。一种方法是用另一个元素将其包装起来,并在该元素上设置 height: 0; overflow: hidden;
。
有三种类型的元素不受此规则约束:图像、画布和视频。这些类型的元素可以具有 display: none
并仍然可以在 -moz-element
中使用。事实上,它们甚至不需要在 DOM 中。
新的 DOM API
document.mozSetImageElement
我们在 document 对象中添加了一个新方法:document.mozSetImageElement(<elementID>, <element>)
。
考虑以下代码段
var slide5 = document.getElementById("slide-5");
document.mozSetImageElement("current-slide", slide5);
现在,所有具有 background-image: -moz-element(#current-slide)
的元素都将绘制 ID 为 slide-5
的元素,即使存在 ID 为 current-slide
的真实元素!
调用 document.mozSetImageElement("current-slide", null)
将停止覆盖。
此 API 在各种用例中都非常方便。我之前部分已经提到了其中之一:使用 mozSetImageElement
,您可以使用不属于 DOM 树的画布和图像元素。
var img = new Image();
img.src = "my_image.png";
document.mozSetImageElement("image", img);
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 100;
var ctx = canvas.getContext("2d");
// ... draw into ctx ...
document.mozSetImageElement("canvas", canvas);
另一个受益于 mozSetImageElement
的场景涉及 JavaScript 实用程序库。您可能有一个这样的函数
var runningNumber = 0;
function addReflectionToElement(reflectedElement) {
var referenceID = "reflected-element-" + runningNumber++;
var reflection = document.createElement("div");
reflection.className = "reflection";
reflection.style.backgroundImage =
"-moz-element(#" + referenceID + ")";
document.mozSetImageElement(referenceID, reflectedElement);
// ... insert reflection into the DOM ...
}
这样,您可以最大程度地减少实用程序函数的影响,因为您不必操作传入元素的 ID。
最后,mozSetImageElement
还允许您引用来自其他文档的元素,例如来自 iframe 内部——当然,要遵守同源策略。
-moz-element
用于 SVG 绘制服务器:图案和渐变
如果您曾经手动编写过任何 SVG,那么您就会熟悉 绘制服务器 的概念:当您不只是想要单一纯色时,可以在 fill
和 stroke
属性中使用这些东西。现在,您也可以在 HTML 元素上使用它们,使用 -moz-element
This element has both types of SVG paint servers
in its background: a pattern and a gradient.
请注意,由于我们的 新的 HTML5 解析器,我们甚至不需要使用 XHTML 就能嵌入 SVG。
此功能与 CSS 渐变 和 SVG 图像的功能重叠,但在某些情况下非常有用,例如动画。例如,假设您想创建一个具有如下所示的动画渐变的进度条
您可以使用 CSS 渐变和一些定期更新 background-position
属性的 JavaScript 来实现这一点。但您也可以使用通过 SMIL 进行动画处理的 SVG 渐变,无需任何 JavaScript
可以使用 CSS 动画实现相同的效果,但在 Gecko 中尚未实现这些动画之前,您可以使用此方法。
对 SVG 作为 CSS 背景的支持(错误 276431)将很快添加。
此外,这里还有一个供您参考的 CSS + SVG 吃豆人。
应用
我对 -moz-element
的用法还有两个建议
反射
什么是反射?
#reflection {
/* It's a copy of the original element... */
background: -moz-element(#reflected-element)
bottom left no-repeat;
/* ... turned upside down ... */
-moz-transform: scaleY(-1);
/* ... with a gradual fade-out effect towards the bottom. */
mask: url(#reflection-mask);
}
因为我们可以对反射应用任意样式,所以我们可以生成诸如 动画水波纹 之类的效果。
花哨的幻灯片切换
在此演示中,我希望有一个幻灯片切换效果,看起来像是上一张幻灯片的上半部分向下折叠以显示下一张幻灯片
您将如何实现这一点?您显然需要使用某种转换,但要在哪个元素上使用?幻灯片的上半部分需要与下半部分具有不同的转换,因此您不能只在幻灯片本身上设置转换。
我最终创建了四个新元素:#previousUpper、#previousLower、#nextUpper 和 #nextLower。我将它们放入一个名为 #transition 的单独容器中,该容器仅在转换正在进行时可见。然后,我为它们提供了正确的尺寸,并使用 background-image: -moz-element(#previous/nextSlide)
和正确的 background-position
将上一张/下一张幻灯片的相应子图像分配给它们。最后,我在这些辅助元素上设置了转换。
不过,它的代码变得相当复杂,因此我将直接引导您到 完成的演示。
更多?
我目前对 -moz-element
演示的想法已经用完了,但肯定还有更多可以使用它的东西。现在轮到你了!
鸣谢
这里的大部分功劳应该归于 Robert O’Callahan,他早在 2008 年就完成了 最初的 实现。不过,在他最初的实验之后,他不得不处理更重要的事情,因此他的补丁休眠了一年左右,直到他在 2009 年 7 月 开始了一个新闻组主题来确定正确的 API。不久之后,Ryo Kawaguchi 恢复了 roc 的工作,并在 他在 Mozilla 实习的最后几周 致力于此。一年后,我使补丁准备就绪以供审查,并将其推动到最终阶段直至签入。
与 mozRequestAnimationFrame 相同的警告适用:-moz-element
和 document.mozSetImageElement
是实验性 API。我们不保证永远支持它们,并且我们不会鼓励网站依赖它们。我们实现了它们,以便人们可以对其进行实验,并且我们可以收集反馈。我们将建议将其作为标准(显然,不带 moz 前缀),并且作者对我们实现的反馈将帮助我们制定更好的标准。
关于 Paul Rouget
Paul 是一位 Firefox 开发人员。
37 条评论