⬆️ ⬇️

Firefox 4: Draw arbitrary elements as backgrounds with -moz-element

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 :
  1. 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.
  2. 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.
  3. The background can be done any element of HTML. Even <iframe> :



    [ ]



    Even <video> :



    [ ]



    And even the canvas <canvas> :



    [ ]
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:



[process indicator]



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.

Source: https://habr.com/ru/post/102624/



All Articles