Поль Руже: Это блогозапись нашего гостя, Маркуса Стэнджа. Маркус обыкновенно работает над реализацией темы оформления Firefox для Маков, но на сей раз он совершил небольшую окольную прогулку по движку макетирования в Gecko, реализуя-moz-element.
В четвёртой бета-версии нового Файерфокса мы представляем вам новое расширение
<p id="myBackground1" style="background: darkorange; color: white; width: 300px; height: 40px;">
This element will be used as a background.
<!-- Этот элемент послужит фоном. -->
</p>
<p style="background: -moz-element(#myBackground1); padding: 20px 10px; font-weight: bold;">
This box uses #myBackground1 as its background!
<!-- Этот прямоугольник использует #myBackground1 в качестве фона! -->
</p>
![показать пример [показать пример]](http://hacks.mozilla.org/wp-content/uploads/2010/08/basicexamplescreenshot.png)
Изображение -moz-element() срабатывает совершенно так же, как и привычное изображение url(). Это значит, что оно управляется всеми привычными свойствами фонов: background-position, background-repeat, и даже background-size.
Используя background-size, вы можете создать миниатюру (thumbnail) того элемента, который используется в качестве фона — вот пример:
<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;
}
![показать пример [показать пример]](http://hacks.mozilla.org/wp-content/uploads/2010/08/thumbnailscreenshot.png)
Имейте в виду три обстоятельства
- Фон — живой: что бы ни происходило в том элементе, который указан в свойстве
-moz-element, фон будет отражать его изменения. Он также будет отображать выделение текста курсором, моргание текстового курсора, и так далее. - Фон — просто видимость. На нём нельзя жмякнуть мышою и попасть к элементу-первоисточнику изображения. Так он устроен.
- Фоном можно сделать какой угодно элемент HTML.
Даже <iframe>:
Даже <video>:
И даже холст <canvas>:
Использование холста в качестве фонового изображения также поддерживает и Webkit, посредством
Зацикливание отрисовки
Беглое замечание по поводу рекурсивных ссылок: если вы попробуете отрисовать таким образом элемент, который и сам отрисован при помощи
Сокрытие элемента-первоисточника
Подчас вы можете не захотеть того, чтобы первоначальный элемент был видимым — а оставить на виду только фон
Вместо этого вам нужно предотвратить отрисовку элемента на экране, не пряча его впрямую. Один из возможных способов — поместить этот элемент внутрь другого, и задать этому другому «height: 0; overflow: hidden;» в CSS.
Три типа элементов являются исключением из этого правила: изображения, холсты и видеозаписи. Этим видам элементов дозволяется иметь свойство «display: none»
Новый DOM API:
document.mozSetImageElement
К объекту document мы добавили новый метод: document.mozSetImageElement(ID_элемента, элемент).
Рассмотрим следующие две строки кода:
var slide5 = document.getElementById("slide-5");Теперь все те элементы, которые наделены свойством
document.mozSetImageElement("current-slide", slide5);
Вызов 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");
//… далее рисуем через ctx …
document.mozSetImageElement("canvas", canvas);
Другая ситуация, в которой вызов mozSetImageElement оказывается полезен — создание библиотеки джаваскриптовых функций. Например, у вас может получиться вот такая функция:
var runningNumber = 0;Следуя таким путём, вы можете уменьшить побочный эффект от применения библиотечной функции: ей не придётся манипулировать ID того элемента, который ей передан.
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);
//… и теперь вставляем reflection в DOM …
}
И наконец, mozSetImageElement также позволяет ссылаться на элементы других документов (например, внутри <iframe>); при этом, разумеется, действуют обычные требования ко взаимодействию документов (единство их происхождения).
-moz-element
для серверов отрисовки SVG: узоры и градиенты
Если вам доводилося писать SVG вручную, то вам наверняка знакомо понятие серверов отрисовки (paint servers): это те элементы, узоры
<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.
<!-- Фон этого элемента использует оба типа
серверов отрисовки SVG: и узор, и градиент. -->
</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>
![показать пример [показать пример]](http://hacks.mozilla.org/wp-content/uploads/2010/08/svgpatterngradient.png)
Обратите внимание, что благодаря нашему новому парсеру HTML5 нам не обязательно использовать XHTML для того, чтобы заработал внедрённый код SVG.
Вышеописанная возможность дублирует ужé существующие возможности градиентов CSS и иллюстраций SVG, однако и она бывает необычайно полезною в некоторых ситуациях — например, в анимациях. Предположим, вам надобно создать индикатор процесса, снабжённый анимированным градиентом, наподобие вот этого:
![[индикатор процесса]](http://hacks.mozilla.org/wp-content/uploads/2010/08/flowinggradient.gif)
Вы могли бы достичь желаемого, используя градиент CSS и некоторый джаваскрипт, периодически обновляющий свойство background-position. Однако также вы могли бы использовать градиент SVG, анимированный посредством SMIL, и оттого не требующий вообще никакого джаваскрипта:
<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>
Того же можно достигнуть
Поддержка изображений SVG в качестве фонов CSS (баг 276431) также вскоре будет обеспечена.
И нате ещё пример: Pacman на CSS и SVG.
Приложения
У меня есть ещё пара предложений насчёт использования
Отражения
Что такое отражение?
#reflection {
/* Отражение — это копия первоначального элемента… */
background: -moz-element(#reflected-element)
bottom left no-repeat;
/* … отражённая сверху вниз … */
-moz-transform: scaleY(-1);
/* … и с постепенным затемнением от верха к низу. */
mask: url(#reflection-mask);
}
![показать пример [показать пример]](http://hacks.mozilla.org/wp-content/uploads/2010/08/reflectionscreenshot.png)
Так как к отражению мы можем применять какие угодно стили, то можно порождать эффекты наподобие анимированных кругов на воде.
Шикарные переходы между слайдами
В этом демонстрационном примере мне хочется достигнуть такого зрелищного перехода между соседними слайдами, который выглядит так, как если бы верхнюю половину предыдущего слайда завёртывали книзу, открывая под ним следующий слайд:
На этом месте во блоге Mozilla Hacks стоит видеозапись, подключённая элементом <video>, так что показать её на Хабрахабре не получится.Как бы вы реализовали эту задумку? Несомненно, понадобилось бы
В итоге я создал четыре новых элемента (#previousUpper, #previousLower, #nextUpper и #nextLower) и поместил их в отдельный контейнер (под названием #transition), который становится видимым только во время перехода от слайда к слайду. Тогда я присваиваю им правильные размеры и налагаю соответствующую часть изображения от предыдущего или последующего слайда, используя background-image: -moz-element(#previous/nextSlide) и правильное значение свойства background-position. А затем я налаю на эти вспомогательные элементы желаемое преобразование.
Код этого примера получается весьма непростым, правда... — так что я просто направлю вас к окончательной демонстрации его.
Ещё?
У меня сейчас закончились замыслы примеров
Благодарности
Бóльшую часть благодарности по этому поводу заслуживает Robert O’Callahan, который сготовил первоначальную реализацию ещё в 2008 году. После своих первоначальных экспериментов, правда, ему пришлось плотно работать над более важными делами, так что патчи его пролежали в бездействии почти год, покуда (в апреле 2009 года) он не начал обсуждение в группе новостей о том, каким должен стать подходящий API. Вскоре после этого Рё Кавагучи возродил труды Роберта и все последние недели своей стажировки в Мозилле посвятил им. Ещё через год я подготовил этот патч на рецензирование (review) и провёл его через итоговые стадии, вплоть до включения в код Файерфокса.
Напоследок изложу такое же предупреждение, которое mozRequestAnimationFrame касалось: