По умолчаниюСветлая версия
↑ перейти к списку статей

Галерея на CSS3

Совсем недавно я озадачился попробовать css3-плюшки в действии. Посмотреть на что они годны в реальности. Мой взор пал на знакомые всем галереи fancybox и т.д. Другими словами — решил сделать подобие js-галереи, но только на чистом html+css.
Приступим.
С расположением картинок я особо не заморачивался, выстроив их в «стенку» через float:left. Родителем для изображения выступила ссылка (тег «a»), почему – станет понятно ниже. Т.к. я решил сделать четыре ряда по четыре картинки, задаем им по 25% высоты и ширины. Бордеры «помещаем» в контейнер через box-sizing. Выглядит это так:

a{
float: left;
width: 25%;
height: 25%;
position: relative;
border: 1px solid #333;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}

Теперь работаем с изображением. Задаем ему размеры 100%, позиционирование абсолютом и transition. Код прилагается:
a img{
display: block;
width: 100%;
height: 100%;
-webkit-transition-property: width, height; /* указываем, какие свойства нам надо изменить*/
-webkit-transition-duration: 300ms; /* указываем, с какой скоростью надо вернуть изображение в исходный вид*/
-moz-transition-property: width, height;
-moz-transition-duration: 300ms;
-o-transition-property: width, height;
-o-transition-duration: 300ms;
position: absolute;
opacity: 0.3; /* делаем прозрачность для красоты*/
cursor: pointer;
}

В одном из вариантов галереи я решил сделать подпись фотографиям. Реализовал через псевдоэлемент :after.

a:after {
display: block;
position: absolute;
width: 100%;
height: 100%;
content: "Studio.com";
color: #eaeaea;
font-family: "Trebuchet MS";
font-size: 16px;
opacity: 0.5;
}

Думаю, тут все понятно.

Встал вопрос, по какому действию открывать изображение. Ведь необходимо, чтобы оно открылось и осталось в этом состоянии, пока мы не засмотримся. Выход нашел в псевдоклассе :focus. А так как он работает только для полей формы и ссылок, нам и понадобился тег «a»
Оформляем:

a:focus img{
width: 250%; /* до такого размера мы увеличили изображение*/
height: 250%;
position: absolute;
opacity: 1; /* прозрачность стала не нужна*/
z-index: 1; /* чтобы фотография разворачивалась поверх всех изображений*/
-moz-box-shadow: 0 0 15px 2px #000;
-webkit-box-shadow: 0 0 15px 2px #000;
box-shadow: 0 0 15px 2px #000; /* добавляем немного красоты */
-webkit-transition-property: width, height; /* делаем «сворачивание» изображения*/
-webkit-transition-duration: 2s; /* указываем, с какой скоростью нам надо увеличить изображение*/
-webkit-transition-delay: 0.3s; /* как долго будет думать браузер, перед тем, как развернуть фотографию*/
-moz-transition-property: width, height;
-moz-transition-duration: 2s;
-moz-transition-delay: 0.3s;
-o-transition-property:width, height;
-o-transition-duration: 2s;
-o-transition-delay: 0.3s;
cursor: default;
}

Заметка. Псевдокласс :focus не совсем корректно работает с бразуером Chrome, выход нашел путем добавления ссылке tabindex.

В принципе все уже готово и можно начать использовать. Но вот беда — все изображения разворачиваются с левого верхнего угла в правый нижний, и не всегда это сыграет на руку. Ведь если эта галерея окажется около правой или нижней границ окна браузера, то развернувшееся изображение будет образовывать соответствующие скролл-бары. Как от этого избавиться? На выход пришел псевдокласс :nth-child, с его возможностью задавать периодичность применения свойств:

a:nth-child(4n+4) img, a:nth-child(4n+3) img{
right: 0;
} /* каждый четвертый элемент начиная с 3-го и 4-го будут разворачиваться от правой границы окна браузера*/

a:nth-child(n+9) img{
bottom: 0;
} /* все элементы, начиная с девятого начнут разворачиваться снизу*/

Т.к. сетка у меня 4*4, то в этом случае 12 элемент, например, будет разворачиваться снизу и справа в левый верхний угол. Таким образом у нас все изображения будут показываться внутри самого контейнера с изображениями. Попутно решили проблему с динамически добавляемыми изображениями – нам не надо присваивать классы — :nth-child позаботится об этом сам.

Ну теперь точно все… А как принудительно закрыть изображение? Резонный вопрос. Решаем. Раз у нас фотография открывается по «фокусу», то чтобы ее закрыть, нам надо убрать с нее фокус. Здесь я сильно не заморачивался и решил сделать одну общую «кнопку» и повесить ее в правый верхний угол от галереи. Из примечательного здесь то, что я ее сделал обычным плюсом, повернув его на 45 градусов и добавил к нему тень:

-webkit-text-shadow: 0px 0px 5px #222;
-moz-text-shadow: 0px 0px 5px #222;
text-shadow: 0px 0px 5px #222;
-moz-transform: rotate(45deg);
-o-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
cursor: pointer;

Однако мы привыкли, что один элемент может зависеть от другого и реагировать на его действия только если он является потомком. А плодить 20 потомков неохота(кстати, по этой же причине я сделал всего одну кнопку.)
Нам на помощь пришел селектор обобщенных родственных элементов «~». В итоге мы сделали один элемент в разметке и поместили его в контейнер к нашим изображениям, чтобы они имели одного общего родителя. Ну и применяем стандартный прием:

.closed{
display: none;
}
a:focus~.closed{
display: block;
}

Теперь, если мы нажмем на любую из фотографий, у нас появляется в правом верхнем углу крестик, при клике на который изображение сворачивается. И крестик, соответственно, исчезает тоже.

Примеры(откроются в новом окне):
первый вариант
второй вариант
Поковырять код можно здесь и здесь

Кнопки для сайта

11 комментариев: Галерея на CSS3

  1. Серёга говорит:

    Привет! У меня сетка 3х3 как мне сдалать чтобы каждый 2 элемент разворачивался вправо и влево одновременно????

    • admin говорит:

      Я не очень понимаю, что значит одновременно и вправо и влево. Закиньте свой пример на http://jsfiddle.net/ , разберемся.

  2. Андрей говорит:

    Очень интересная галерея. а что нужно поправить в коде, что бы при кликании на фото открывалась другая картинка, которую не видно в этой галерее…??

    • Alpatriott говорит:

      В контейнер со ссылкой надо помещать два изображения. Нужное из них скрывать через visibility и z-index, например. А по фокусу менять им это свойство. На неделе, если будет время, сделаю наглядное решение.

      • Андрей говорит:

        Alpatriott, приветствую!
        Спасибо за ответ.
        А вот еще вопрос, выйти из положения можно с помощью контейнеров (я так понимаю слоев)? Либо же реально сделать с помощью таблицы. Таблица для меня вроде как проще, потому как планирую каждое изображение подписать, что удобно сделать в ячейке ниже.
        Только вот в этом случае нужно поверх таблицы размещать еще и контейнера?

        • Alpatriott говорит:

          Нет, с таблицей здесь не получится. Т.к. в ней не работает одно из ключевых свойств галереи — позиционирование.

  3. Андрей говорит:

    Alpatriott, приветствую!
    Хотелось подитожить… Задача стоит разместить первичные картинки, можно и в контейнере – как это сделано в вышеприведенном примере не используя таблицу. К каждой картинке нужно будет демонстрировать еще 3-4шт, которые относятся к первичной. Каждая картинка должна быть подписана. При наведении курсора – должна появляться увеличенная следующая за первой картинка.
    Если вы говорите, что можно реализовать только с помощью контейнеров, получается, что нужно выстроить 4-5 контейнеров друг за другом, поместить в них картинки а дальше с помощью visibility, z-index, focus пытаться решить задачу. Так?
    Как вы считаете — это возможно только с помощью css?

    • Alpatriott говорит:

      Насколько я себе представил вашу задачу, да, можно это сделать на css.

  4. Александр говорит:

    Возможно ли данное решение применить к галерее видео с yuotube? Или контейнерах может быть только изображение?

    • Alpatriott говорит:

      Очень маловероятно.
      Т.е. в контейнерах может быть что угодно, но вот с запуском видео и сворачиванием контейнера есть проблемы.
      Видимо, сам плеер вылавливает :focus и тем самым сбивает его с тега a, заставляя последний свернуться в исходное положение.

  5. Матвей говорит:

    Спасибо тебе за полноценную галерею, очень полезный урок, а более того хочу сделать на сайте себе такую же :)