Сегодня к нам пришло письмо от нашего гостя Andy Walpole который делится своим опытом создания Lightbox Ultra расположенный на Mozilla Demo Studio. Несколько лет назад разработчик Lokesh Dhakar создал сценарий лайтбокса с Prototype и script.aculo.us. Его плавная анимация и гладкая эстетика была хитом в обществе веб-дизайнеров, и он был использован во многих проектах.
Затем было много подражателей — Fancybox и Thickbox, но лайтбокс по прежнему остается излюбленным способом показа изображения для пользователя. Это, прежде всего, связано с его 3D-анимации и затемнённым фоном, который позволяет пользователю просматривать изображение не отвлекаясь на другие детали.
CSS анимацией я впервые начал пользоваться еще несколько лет назад, многие программисты используют её для воплощения своих идей. Действительно, существует реальное увлечение CSS-анимацией, но это только эксперименты. В ближайшем будущем CSS вытеснит JavaScript на уровне визуализации, поэтому сейчас мы будем использовать для нашей цели именно CSS.
Совсем недавно я соделал проект на CSS, он был выставлен на сайте Mozilla Demo под названием Lightbox Ultra. Его ядро в частности — CSS3, 3D-анимация — но в процессе создания демо я понял, что нужно добавить JavaScript, для определённых удобств и конструктивных особенностей.
В данном руководстве нет пояснения мелких деталей кода, который я написал для моего Lightbox проекта. Что бы не запутать читателя. Вместо этого, я объясню некоторые из основных концепций создания современного Лайтбокса. Таким образом, вы можете использовать эти идеи в своем собственном проекте.
CSS и Лайтбокс
Начнем с HTML:
Я использовал списки определений, но я мог бы так же легко использовать неупорядоченные списки. Обратите внимание, как блок кода для каждого изображения делится на две части — одна для эскизов, а другая для полноразмерного изображения.
Полноразмерное изображение должно быть установлено с "display: none", так что начальным состоянием для пользователя будет только эскиз:
Полноразмерное изображение появляется после взаимодействия пользователя с миниатюрами.
Для этого нужно использовать события JavaScript. Изменим небольшую часть кода CSS, с использованием "display:block" когда пользователь кликает на иконку (Здесь я используюquery Selector (), который имеет только частичную кросс-браузерную поддержку):
var thumbnail = document.querySelector(".first-image img");
var fullSize = document.querySelector(".second-image img");
thumbnail.onclick = function () {
fullSize.style.display = "block";
}
Сейчас мы должны использовать события JavaScript в CSS для псевдо-класса :target. Я не знаю, чьей идеей было представить :target в спецификацию CSS3, но его включение стало значительным актом изобретательности.
.second-image dl:target {
display: block;
}
:target работает с использованием фрагмента URL. Ссылка на эскиз имеет следующий фрагмент: "#block-1". Это идентификатор полного размера блока-1. При нажатии на ссылку с фрагментом, запускается HTML с его ID, до тех пор, конечно, пока вы не укажите его в таблице стилей.
Потому что он отличается от других CSS, :target может показаться немного странным на первый взгляд. Лучший способ познакомиться с ним это применять его на практике в своем собственном коде.
В будущем :target станет одной из наиболее часто используемых функций CSS3. Правда у него есть один минус, он не поддерживается в Explorer 8 и ниже. Я расскажу вам как использовать его альтернативу в следующем разделе.
CSS keyframe довольно прост:
/* animation for main image */
.second-image dl:target .animation {
-moz-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
-webkit-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
-ms-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
-o-animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
animation: image3D 2000ms cubic-bezier(0.950,0.050,0.795,0.035);
}
/* image3D is used on the main image */
<hh user=-moz-keyframes> image3D {
0% {
-moz-transform: rotateY(90deg);
}
100% {
-moz-transform: rotateY(0deg);
}
}
<hh user=-webkit-keyframes> image3D {
0% {
-webkit-transform: rotateY(90deg);
}
100% {
-webkit-transform: rotateY(0deg);
}
}
<hh user=-o-keyframes> image3D {
0% {
-o-transform: rotateY(90deg);
}
100% {
-o-transform: rotateY(0deg)
}
}
<hh user=-ms-keyframes> image3D {
0% {
-ms-transform: rotateY(90deg);
}
100% {
-ms-transform: rotateY(0deg);
}
}
<hh user=keyframes> image3D {
0% {
transform: rotateY(90deg);
}
100% {
transform: rotateY(0deg);
}
}
Я не буду подробно объяснять код, приведенный выше, потому что эта статья не является руководством по CSS3 анимации. Для этого я бы посоветовал Вам прочитать статью написанную Tim Van Damme, Louis Lazaris и Tom Waterhouse.
Обратите внимание, в приведенном выше коде я использовал Webkit, Firefox, Microsoft и Opera prefixes. Пока еще нет поддержки ключевых кадров в Internet Explorer или Opera.
JavaScript и Lightbox
На моей странице в Mozilla Demo у меня было много забавных вещей при создании этого лайтбокса. Я использовал box-shadows, функции Calc (), градиенты и CSS3 преобразования. Если отключить JavaScript в вашем браузере и попробовать запустить демо в современных браузерах, увидите, что оно находится в отличном рабочем состоянии.
Тем не менее, есть это некоторые трудности с CSS3, к которым мы будем применять дополнительные методы.
Во-первых, анимация CSS3 только срабатывает один раз. Этот вопрос уже хорошо описали Oli Studholme и Chris Coyier.
CSS3 keyframes будут работать только раз, если не обновлять страницу. Одним из обходных путей заключается использование transitions вместо keyframes. Другой способ заключается в использовании JavaScript для восстановления узла, каждый раз, когда анимация запускается.
Сейчас нужно удалить старый класс в методе change_animation (), дублировать соответствующую часть DOM, добавить случайный класс, удалить интернет узел и заменить его дубликатом DOM:
change_animation: function (htmlElement) {
var items, random, regEx, result, key, mainBlock, cloneBlock, parentBlock;
// below finds the unique key which is in the parent div id
function removeArrayElement(element, index, array) {
return (!element.search(_private.REMOVE_SEARCH));
}
regEx = /.([0-9]+)$/;
result = regEx.exec(htmlElement.parentNode);
key = result.filter(removeArrayElement).toString();
// this unique key is then used to find the large image in the overlay
// this is an alternative to some bonkers DOM transversal method
mainBlock = document.querySelector("#block-" + key + " img");
// remove previous animation class
mainBlock.removeAttribute("class", "");
// In order for CSS animation to run more than once on the same element
// It is necessary to rebuild the node
// See for further details: http://css-tricks.com/restart-css-animation/
cloneBlock = mainBlock.cloneNode(true);
// select a class at random
items = this.classes;
random = items[Math.floor(Math.random() * items.length)];
// rebuild the html adding the new class
cloneBlock.setAttribute("class", random);
parentBlock = mainBlock.parentNode;
parentBlock.removeChild(mainBlock);
parentBlock.appendChild(cloneBlock);
}
Я уверен, что вы могли бы написать не такой большой код, если бы вы использовали JQuery.
Глобальный пользовательский интерфейс:
lightbox.init({
// declare CSS classes that are used for animation
classes: ['image3D', 'flipper', 'bulge', 'bouncing', 'side-spin', 'top-spin', 'shadow-play', 'rush']
});
Для того чтобы изменить анимацию нужно просто добавить новый класс в CSS и JavaScript. Упомянутый выше, "top-spin" выглядит следующим образом:
/* TOPSPIN */
.top-spin {
-moz-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
-webkit-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
-ms-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
-o-animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
animation: topSpin 2000ms cubic-bezier(0.000, -0.600, 0.000, 1.650);
}
<hh user=-moz-keyframes> topSpin {
0% {
-moz-transform: rotateX(0deg);
-moz-transform-origin: 0% 50% 0;
}
100% {
-moz-transform: rotateX(360deg);
-moz-transform-origin: 0% 50% 0;
}
}
<hh user=-webkit-keyframes> topSpin {
0% {
opacity: 0.1;
-webkit-transform: rotateX(0deg);
-webkit-transform-origin: 0% 50% 0;
}
100% {
opacity: 1;
-webkit-transform: rotateX(360deg);
-webkit-transform-origin: 0% 50% 0;
}
}
<hh user=-o-keyframes> topSpin {
0% {
-o-transform: rotateX(0deg);
-o-transform-origin: 0% 50% 0;
}
100% {
-o-transform: rotateX(360deg);
-o-transform-origin: 0% 50% 0;
}
}
<hh user=-ms-keyframes> topSpin {
0% {
-ms-transform: rotateX(0deg);
-ms-transform-origin: 0% 50% 0;
}
100% {
-ms-transform: rotateX(360deg);
-ms-transform-origin: 0% 50% 0;
}
}
<hh user=keyframes> topSpin {
0% {
transform: rotateX(0deg);
transform-origin: 0% 50% 0;
}
100% {
transform: rotateX(360deg);
transform-origin: 0% 50% 0;
}
}
Вторая проблема, стоящая перед Lightbox CSS3 является отсутствие поддержки в Internet Explorer. К сожалению, версии 8 и ниже не признают псевдо-класс :target.
Один из способов обойти эту проблему, использовать Polyfill такие как Dean Edwards IE7.js или Keith Clarke's Selectivizr (последний имеет поддержку только IE8).
Он имеет полную поддержку CSS3 так же как и Sizzle. Я полагаю также, вы можете использовать JQuery и Dojo.
Тем не менее, моя цель для демо: создать его полностью независимым от любой другой библиотеки JavaScript.
Если браузер не признает CSS псевдо-классы или псевдо-элементы, тогда необходимо разобрать весь блок кода. Это означает, что невозможно применить использование CSS стилей объекта, для блока в котором используеться :target.
Мое решение было использовать XMLHttpRequest API для сохранения стилей в памяти, а так же все изменения :target с классом ieTarget, удалить старые таблицы стилей, а затем добавить новые измененные к .IeTarget, потом динамически добавлять и удалять его из HTML в зависимости от действий пользователя.
Правда, это довольно радикальный ход и есть возможность оставить много потенциальных ошибок и проблем.
Наконец, если вы собираетесь использовать JavaScript для лайтбокса, то почему бы не использовать новый полноэкранный API. Он был введен в Webkit в 2011 году и сделал свое первое появление в Firefox в начале 2012 года.
API довольно прост в реализации:
full_page: function () {
var img, x, docElm, l;
img = document.querySelectorAll(".first-image img");
for (x = 0, l = img.length; x < l; x += 1) {
// call full screen when clicking on the thumbnail
img[x].addEventListener("click", function (evt) {
docElm = document.documentElement;
if (docElm.requestFullScreen) {
docElm.requestFullScreen();
_private.add_warning();
_private.request_smallscreen();
} else if (docElm.mozRequestFullScreen) {
docElm.mozRequestFullScreen();
_private.add_warning();
_private.request_smallscreen();
} else if (docElm.webkitRequestFullScreen) {
docElm.webkitRequestFullScreen();
_private.add_warning();
_private.request_smallscreen();
}
}, false);
} // end for loop
}
Теперь можно получить доступ к глобальным объектам в нашем интерфейсе, с полноэкранным режимом.
lightbox.init({
// declare whether you want to use the Full-screen API
fullscreen: false,
// declare CSS classes that are used for animation
classes: ['image3D', 'flipper', 'bulge', 'bouncing', 'side-spin', 'top-spin', 'shadow-play', 'rush']
});
Автор: Lecaw