Создание современного лайтбокса на CSS3 и JavaScript

в 4:17, , рубрики: css, css3, javascript, веб-дизайн

image

Сегодня к нам пришло письмо от нашего гостя 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:

image

Я использовал списки определений, но я мог бы так же легко использовать неупорядоченные списки. Обратите внимание, как блок кода для каждого изображения делится на две части — одна для эскизов, а другая для полноразмерного изображения.

Полноразмерное изображение должно быть установлено с "display: none", так что начальным состоянием для пользователя будет только эскиз:

image

Полноразмерное изображение появляется после взаимодействия пользователя с миниатюрами.

Для этого нужно использовать события 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

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js