Даркбокс

Читайте про более новую версию скрипта в записи «Возвращение Даркбокса»

К счастью, прошли времена, когда для загрузки картинки разработчики открывали отдельное окно браузера. У нас нынче вебдваноль, поэтому открывать отдельные окна это моветон, а современные JS-фрейворки дают возможность показать картинку по-настоящему красиво без особых сложностей.

И вроде решений для этого написано уйма — бери, да используй. Но вот беда — все они сделаны по принципу «plug-n-play», мол подключай и не парься. В итоге эти решения снабжены всевозможными фичами, которые позволяют открывать окошки с любым содержимым, передвигаться по галерее при помощи клавиатурных сокращений и многое-многое другое. Классно, ведь! Нет? Ну, не совсем — в итоге код такого плагина распухает от всех этих возможностей, которыми никто не будет пользоваться, и непонятных HTML-шаблонов, содержащих сомнительный код — и тут же стили к нему. А вот это уже не слишком классно…

Если страдать синдромом аккуратизма определённой тяжести, то подход а всё равно это JS, какая нафиг разница становится совсем неприемлем. А переписывание чужих решений практически равноценно написанию собственного — чем, собственно, я и занялся при подготовке новой версии этого сайта.

Начиналось всё с простых, но очень правильных принципов:

В итоге, благодаря применению jQuery, получилась не слишком сложная функция и набор стилей к ней, которые решают простую задачу — открытие одной картинки с затемнением всего окна.

Даркбокс — пример работы, весь код в одном файле.

Принципы работы

Очень полезно начинать описание задачи не с фраз вроде «а там такая штука крутится полупрозрачная, а потом пфф! и блёстки…». Поэтому я начал с простого: у меня есть просто ссылка на просто картинку, и только если у пользователя включён JS, ссылка не срабатывает, а открывается то самое полупрозрачное с блёстками.

Контейнер для открытия картинки представляет собой блок вырванный из потока и спозиционированный при помощи position:fixed. Внутри него расположено само полупрозрачное затемнение и блок загрузчика с крутящимся псевдо-датчиком загрузки. Все эти объекты создаются динамически и складываются в нужном порядке:

<div class="popup-frame">
    <div class="popup-shadow"></div>
    <div class="popup-loader"></div>
</div>

Это дело красиво появляется и дальше в загрузчик вкладываются пока невидимые картинка и кнопка закрытия. Атрибут src берётся из href ссылки, alt из её title:

<img src="…" alt="…"/>
<span title="Закрыть"></span>

Сразу после загрузки нашей картинки, загрузчику выдаётся класс popup-loaded, который отключает датчик загрузки. Дальше он плавно меняет свои размеры, смещение, прозрачность и, наконец, ещё раз сменив класс на popup-canvas, показывает нам картинку. А на тень, кнопку и Esc вешается обработчик закрытия всей этой красоты.

Таким образом, всё оформление, что не участвует в анимации, применяется при помощи CSS-классов, а не присутствует в JS явно, как очень любят делать все плагинописатели.

Неизбежное исключение

Да, чуть было не забыл про IE. Данному скрипту удалось угодить всем его актуальным версиям, начиная с 5.5 и заканчивая 8.0. Проблемы с position:fixed для IE6 и младше решаются при помощи expression:

* HTML BODY {
    background:url(about:blank) fixed;
    }
* HTML .popup-frame {
    position:absolute;
    top:expression(0+(
        (e=document.documentElement.scrollTop)
        ?e:document.body.scrollTop)+'px');
    }

Правило background:url(about:blank) fixed задаёт пустое фиксированное изображение для того, чтобы позиционирование блока в IE6 работало плавно, без рывков. Прозрачность для всех версий IE решается при помощи filter:alpha(opacity=N), а использование PNG-24 картинки для кнопки, столь же традиционно лечится для IE6 с помощью AlphaImageLoader.

В целом, написание скрипта прошло гладко, как по учебнику, за исключением выходки браузера Opera. Ему, видите ли, не получить размеры динамически созданной и уже загруженной картинки, пока она не будет вставлена в документ. Даже IE5 ничего подобного не вытворял, в прочем, мне не жалко.

Итак, перед вами не претендующее на красоту и универсальность, однако, простое и эффективное решение для открытия картинок в стиле вебдваноль. Если кому-то пригодится — буду только рад.

19 декабря 2008: благодаря внимательности читателей, поправлены некоторые ошибки в IE6, в частности — методика борьбы с дрожащим фоном и expression теперь универсальны и работают как в Standard Mode, так и в Quirks Mode.

Комментарии

47

Спасибо. Единственное НО: мне кажется, что привычнее "закрыть" делать справа от картинки. Когда хотел закрыть рука на автомате потянулась в правый верхний угол. имхо

Очень здорово!

Не подозревал что в обычном лайтбоксе напихано столько не нужных вещей, что js файл можно сократить на столько! Работа сделана не зря - это точно.

Но я рядовой избалованный пользователь, и мне не хватает простой навигации (не клавиатурной) вперед/назад и отображение количества фотографий вместе с порядковым номером текущей фотографии.

Было бы это - я бы забыл про лайтбокс.

Вадим, было не плохо иметь метки к записям и к этой в частности solution (к примеру), чтобы можно было посмотреть все ваши решения по разным проблемам )

Хорошее решение, я бы в точности сделал (концептуально имеется ввиду).

здорово!
осталось добавить поддержку массивов изображений для галлерей

А зачем создавать элементы при открытии картинки? Во первых, это задержит пользователя (немножко), а во вторых — будет создавать всё новые элементы при каждом нажатии. Звучит неэкономно.

Ага! То есть, все-таки, полгода нытья «напиши мне плагин для картинок» — мне, а вся слава в результате тебе?!

А если на странице будут присутствовать select-ы они будут перекрыватся в IE6 ? )

IE8b2, режим совместимости со стандартами - кнопка закрытия в демке попадает девушке на лоб.

Если, честно, скрипт на 4 с натяжкой (если расценивать не как «просто мозг размять», а как претендент на публичный проект):
1) как заметил cogone, в IE 6 select'ы будут просвечивать через фон и box
2) наверно, лучше бы, добавлять динамический контент один раз (например при первой загрузки darkbox'а или при загрузки страницы)
3) для распространения и использования, код удобнее бы обернуть в класс или plug-in для jQuery.

Плюс, если уж начал придираться, то: если картинка по размеру больше чем окно браузера, то darkbox «улетает» за границы. :))

Ви прав, динамический контент нужно добавлять один раз, а не при каждом попапе. Кроме этого в функции closeit не помешало бы unbind keydown с документа.
И ещё вот эта конструкция: shadow.click(function(){closeit()}); смело заменяется вот этой: shadow.click(closeit);

Ещё бы он не перебивал CtrlShiftClick, который открывает картинку в фоновой странице, да и ShiftClick, или открыть в новой странице, было бы куда-ни-шло.

А вообще, все эти лайтбоксы есть одно из худших проявлений, можно даже сказать полный уёбдваноль. В особенности, когда не используют a, а в место этого вешают дурные обработчкии на спаны, или там img

«Ещё бы он не перебивал CtrlShiftClick, который открывает картинку в фоновой странице, да и ShiftClick, или открыть в новой странице, было бы куда-ни-шло».

Вот за это всегда не любил такие открывалки. Оно, конечно, красиво. И, если на странице одна-две картинки, даже удобно. Но если надо посмотреть несколько картинок, то это просто не работает.

если расценивать не как «просто мозг размять»

В точку. Это как раз мелочь, написанная для конкретной задачи, именно разминка для мозга. По этой же причине в заметке рассматривается только вёрсточная часть этого решения. JS-часть безусловно нужно оптимизировать, чем я и займусь на основе ваших советов )

Спасибо всем за отзывы.

А за что мой коммент был удален? За ссылку, так уберу ее.
Или скрины нужны чтобы убедиться что в ИЕ6 не все так гладко?

А за что мой коммент был удален?

Именно. Просто прямо перед вашим был опубликован подобный комментарий с явным спам-доменом. Прошу прощения.

И спасибо за ваше замечание — публикация готовилась на ходу, поэтому склейка двух версий прошла не очень гладко — кое-что потерялось.

IE8 пока сброшен в IE7-режим, а для IE6 всё поправлено.

akira, спасибо! Внимательно посмотрю твой вариант. На первый взгляд здорово, многому можно научиться. Думаю, что выпущу апдейт в этом ключе.

pepelsbey, спасибо
Ссылку на свой блог больше оставлять не буду, ато мало ли :)

мне кажется, что привычнее "закрыть" делать справа от картинки

Кнопка Esc тоже находится слева и тоже срабатывает ;) Я понимаю, что для вас расположение контролов справа удобнее так же, как для меня слева — из-за Windows и Mac OS X, соответственно.

Я выбрал такой вариант, по праву определяя концепцию этого сайта.

Красиво конечно, но на большом мониторе притормаживает анимация во всех браузерах.

Octane, на маленьких тоже притормаживает.

Решение отличное, но немного смущает размер файла jquery.js, ~55кб. Сжать бы его до 20-30кб, и тогда скрипт возможно, пошел бы в массы.

Скрипт задумывался для случая, когда вы уже используете jQuery. В любом случае, если jQuery ещё и Gzip'овать, то получается порядка 15 кб.

Интересное решение, но жаль лишь что это для пользователей библиотеки jQuery. Лично я с программистом выбрали mootools. Вадим не планируешь работать с этим фреймворком.

Неторопливо, но верно делаю новую версию, помочь с созданием плагинов для mootools и jQuery взялся один хороший JS-программист, так что всё будет ;) …и на качественно новом уровне.

Подозрительное правило filter:true, в данной ситуации, заменяет традиционную методику с фальшивой картинкой и background-attachment:fixed для того, чтобы позиционирование блока работало плавно, без рывков.

Судя по всему, это работает только в Quirks mode. Ваш пример у меня, к сожалению, дергается при скроллинге (кроме стопроцентного блока — он не дрожит никогда, даже без доп. ухищрений). В Standards mode мне удалось победить дрожание, лишь задав body полноценный фильтр — ценой изрядных тормозов.

Все-таки, по моим наблюдениям, самый юзабельный и "кросс-режимный" вариант — это

html { background: #fff url(about:blank) fixed; }

хороший скрипт только под в Internet Explorer 7 если страничка больше самого экрана, не закрашивается она, как то так. А так всё хорошо,

Только, насколько я понимаю, url(a) — это обычный относительный URI (притом скорее всего ошибочный), а about:blank — легитимный URL, заведомо не вызывающий запроса к серверу (полностью "удовлетворяемый" локально). По этим соображениям я его и выбрал...

а в таком случае url(#) не будет ли полноценной аналогией?
Тоже, получается, легитимный URI, не требующий запроса к серверу, только запись короче.

Про "#" я не так уверен, это все-таки ссылка не заведомо "в пустоту", а на тот же документ. А IE6 вообще любит тащить фоновые картинки с сервера по каждому поводу и без повода (по крайней мере, при некоторых настройках и без волшебного средства от Попы:). К тому же был прецедент (хоть и в др. браузере).

Эффект фиксации-то оно дает, но за отсутствие запросов не ручаюсь, чуть позже проверю на полноценном IE6...

Действительно здорово. Надо будет на досуге поковырять.

То есть там 1 скриптик остался+ jQuery?

Прикрутил эту штуку к своему новому проекту :) (только загрузчик нарисовал другой :)). Спасибо, Вадим!
По поводу больших картинок, которые выше высоты окна...Нельзя ли позиционировать их относительно самого окна, а не относительно .popup-loader ? При этом задать им процентную высоту от высоты окна? Пока для больших картинок не нашёл ничего лучшего, чем явно указать высоту height: 550px; width: auto; (но возникла необходимость в кнопке "Увеличить" :))

Если во время загрузки картинки нажать Esc, загрузка прерывается, но затемнение не уходит.
ФФ 3.0

Видимо, нужно до момента полной загрузки ловить Esc и отменять его действие…
Или же ловить его с самого начала и тут же закрывать окно. Спасибо за багрепорт, буду думать.

Даркбокс понравился. Ничего лишнего и правильно работает при прокрутке.
Использовал его на одном сайте, но так как там все на Mootools, пришлось портировать Даркбокс.
Результат тут: http://torqueo.net/files/mootools-darkbox/

Надеюсь, Вадим не против.

2 pepelsbey:

Я не сдержался и сделал порт второй версии Даркбокса. Плюс, добавил опциональный эффект падения окна при закрытии.

Новая версия там же: http://torqueo.net/files/mootools-darkbox/

Про одновременное исчезновение фона и картинки что-то не понял. Помоему и в моем и в вашем скрипта все происходит одинаково - сколько не смотрел, не могу различий найти :(