Paul Rouget: This is a blog of our guest, Marcus Stange. Marcus is usually working on implementing the Firefox theme for Macs, but this time he made a small detour through the prototyping engine in Gecko, implementing -moz-element .
In the fourth beta version of the new Firefox, we present you with a new extension of the
CSS background-image properties : the ability to draw arbitrary elements as backgrounds using
-moz-element (#elementID) .
<p id = "myBackground1" style = "background: darkorange; color: white; width: 300px; height: 40px;">
This element will be used as a background.
<! - This element will serve as a background. ->
</ p>
<p style = "background: -moz-element (# myBackground1); padding: 20px 10px; font-weight: bold;">
This box uses # myBackground1 as its background!
<! - This rectangle uses # myBackground1 as background! ->
</ p>
The
-moz-element () image works exactly the same as the usual
url () image. This means that it is controlled by all the usual background properties:
background-position ,
background-repeat , and even
background-size .
Using the
background-size , you can create a
thumbnail of the element that is used as the background β an example:
<ul id = "thumbnails">
<li style = "background-image: -moz-element (# slide-0)"> </ li>
<li style = "background-image: -moz-element (# slide-1)"> </ li>
<li style = "background-image: -moz-element (# slide-2)"> </ li>
<li style = "background-image: -moz-element (# slide-3)"> </ li>
</ ul>
#thumbnails li {
width: 160px;
height: 120px;
background-repeat: no-repeat;
background-size: contain;
}
')
Keep in mind three things
about -moz-element :
- The background is alive : whatever happens in the element specified by the -moz-element property, the background will reflect its changes. It will also display text selection with the cursor, blinking of the text cursor, and so on.
- The background is just an appearance. It can not zhmyaknut mouse and get to the element of the original source of the image. So it is arranged.
- The background can be done any element of HTML. Even <iframe> :
Even <video> :
And even the canvas <canvas> :
![show example [ ]](http://hacks.mozilla.org/wp-content/uploads/2010/08/canvasscreenshot.png)
Using canvas as a background can be useful in many applications. For example, if you
repaint the image of CSS backgrounds in a browser in sepia , then you no longer need to re-encode the image processed on the canvas,
getting the "data:" URI . Instead, you can make the background image itself a canvas.
Using a canvas as a background image
also supports Webkit , via
-webkit-canvas () .
Draw looping
A quick note about recursive references: if you try to
draw an element in this way, which is itself drawn with -moz-element , then the looping of the drawing will be detected and prevented. So, if you want to paint the
Sierpinski carpet , you have to come up with another way.
Hiding the original element
Sometimes you may not want the original element to be visible - and leave only the
-moz-element background visible. And what then do you have to do? Simply setting β
display: none β or β
visibility: hidden β to the source element will not work, since then there will be nothing to draw against the
-moz-element background, and therefore it will become transparent.
Instead, you need to prevent the element from being drawn on the screen without hiding it directly. One possible way is to put this element inside another, and set this other β
height: 0; overflow: hidden; "In CSS.
Three types of elements are exceptions to this rule: images, canvases, and videotapes. These kinds of elements are
allowed to have the "
display: none " property
and still be used
in -moz-element . Moreover, they may not even be contained in the DOM of the main document.
New DOM API:
document.mozSetImageElement
We have added a new method to the
document object:
document.mozSetImageElement ( element_id , element ) .
Consider the following two lines of code:
var slide5 = document.getElementById ("slide-5");
document.mozSetImageElement ("current-slide", slide5);
Now all those elements that are endowed with the
background-image: -moz-element (# current-slide) property will display the element having the
ID slide-5 - even if
there is an element that has the
ID current-slide !
Calling
document.mozSetImageElement ("current-slide", null) cancels the actual override.
Such an API can come in handy in a variety of practical situations. I indirectly mentioned one of them in the previous subsection: using
mozSetImageElement, you can use canvases and images that are not part of the DOM tree:
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");
// ... further we draw through ctx ...
document.mozSetImageElement ("canvas", canvas);
(
show example )
Another situation in which the
mozSetImageElement call is useful is to create a library of javascript functions. For example, you might get this function:
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);
// ... and now insert reflection into the DOM ...
}
By following this way, you can reduce the side effect of using the library function: it will not have to manipulate the ID of the element that is transferred to it.
Finally,
mozSetImageElement also allows you to reference elements of other documents (for example, inside <iframe>); at the same time, of course, the usual requirements for the interaction of documents (the unity of their origin) apply.
-moz-element
for SVG rendering servers: patterns and gradients
If you finished writing SVG manually, then you probably know the concept of rendering servers (
paint servers ): these are the elements, patterns
and / or gradients that you have to specify in the
fill or stroke attributes when a single-color fill is not suitable. Now they can also be used in the backgrounds of HTML elements using
-moz-element :<p style = "background: -moz-element (#pattern),
-moz-element (#gradient);
padding: 10px; color: white ">
This element has both types of SVG paint servers
in its background: a pattern and a gradient.
<! - The background of this element uses both types.
SVG drawing servers: pattern and gradient. ->
</ p>
<svg height = "0">
<linearGradient id = "gradient" x2 = "0" y2 = "1">
<stop stop color = "black" offset = "0%" />
<stop stop-color = "red" offset = "100%" />
</ linearGradient>
<pattern id = "pattern" patternUnits = "userSpaceOnUse"
width = "60" height = "60">
<circle fill = "black" fill-opacity = "0.5"
cx = "30" cy = "30" r = "10" />
</ pattern>
</ svg>
Please note that thanks to our
new HTML5 parser, we donβt have to use XHTML in order for the implemented SVG code to work.
The above feature duplicates the existing possibilities of
CSS gradients and SVG illustrations, but it is also extremely useful in some situations, for example, in animations. Suppose you need to create a process indicator, equipped with an animated gradient, like this:
You could achieve the desired using a CSS gradient and some javascript that periodically updates the
background-position property. However, you could also use an SVG gradient animated by SMIL, and therefore not requiring any javascript at all:
<div
style = "background: -moz-element (# animated-gradient);">
</ div>
<svg height = "0">
<linearGradient id = "animated-gradient" spreadMethod = "reflect"
gradientUnits = "userSpaceOnUse"
x1 = "16" x2 = "24" y2 = "0">
<animate attributeName = "x1" values ββ= "16; 0" dur = "350ms"
repeatCount = "indefinite" />
<animate attributeName = "x2" values ββ= "24; 8" dur = "350ms"
repeatCount = "indefinite" />
<stop stop-color = "# 0F0" offset = "0" />
<stop stop-color = "# 0D0" offset = "100%" />
</ linearGradient>
</ svg>
(
show example )
The same can be achieved
with CSS animations, however, until they are implemented in Gecko, you can follow the above described path.
Support for SVG images as CSS backgrounds (
bug 276431 ) will also be provided soon.
And here's another example:
Pacman on CSS and SVG .
Applications
I have a couple more suggestions for using
-moz-element :
Reflections
What is reflection?
#reflection {
/ * Reflection is a copy of the original element ... * /
background: -moz-element (# reflected-element)
bottom left no-repeat;
/ * ... reflected from top to bottom ... * /
-moz-transform: scaleY (-1);
/ * ... and with gradual darkening from top to bottom. * /
mask: url (# reflection-mask);
}
Since we can apply any style to the reflection, we can generate effects like
animated circles on the water .
Elegant transitions between slides
In this demo, I want to achieve such a spectacular transition between adjacent slides, which looks as if the top half of the previous slide was wrapped down, opening the next slide below it:
At this place in the Mozilla Hacks blog there is a video, connected by the <video> element, so it will not work to show it on Habrahabr.
How would you implement this idea? Sure, it would take
some kind of conversion, but the transformation of which particular element? The upper half of the slide requires a different transformation than the bottom, so simply applying the conversion to the entire slide will fail.
As a result, I created four new elements (#previousUpper, #previousLower, #nextUpper and #nextLower) and placed them in a separate container (called #transition), which becomes visible only during the transition from slide to slide. Then I assign the correct dimensions to them and impose the appropriate part of the image from the previous or next slide, using
background-image: -moz-element (# previous / nextSlide) and the correct value of the
background-position property. And then I put the desired transformation on these auxiliary elements.
The code for this example is quite complicated, really ... - so Iβll just take you
to the final demonstration of it .
Still?
I have now run out of ideas for the
-moz-element examples
, although, of course, there is still a lot to be done with this property. Now it's your turn!
Acknowledgments
Robert O'Callahan , who prepared the
initial implementation back in 2008, deserves most of this thanks. After his initial experiments, however, he had to work closely on more important matters, so that the patches lay inactive for almost a year, until (in April 2009) he started a
discussion in the newsgroup about what should be a suitable API. Shortly thereafter, Ryo Kawaguchi
revived the works of Robert and devoted all his last weeks of his
internship in Mozille to them. A year later, I prepared this patch for review
(review) and conducted it through the final stages, up to the inclusion in the Firefox code.
Finally, I
βll explain the same warning that
mozRequestAnimationFrame concerned:
both -moz-element and document.mozSetImageElement are experimental APIs. We do not guarantee their endless support, and we do not advocate their use. We implemented them so that people could experiment with them, and we would receive feedback. We will offer these APIs as a standard (but without the βmozβ prefix, of course), so feedback on our implementation will help us improve the future standard.