—»     —»   Галерея с плавными диагональными переходами на CSS3
  Раздел: Руководства   Нет комментариев  

Галерея с плавными диагональными переходами на CSS3



В сегодняшнем руководстве мы хотим рассказать вам о процессе создания галереи с плавными диагональными переходами, основанными на CSS3. Она будет сканировать директорию с изображениями на сервере, а затем отображать их в виде сетки, которая растягивается на все окно браузера. Добавлять новые фотографии будет невероятно просто – вам нужно будет просто скопировать в папку два изображения, - оригинал изображения и миниатюру в размере 150х150 пикселей.


Браузеры, поддерживающие CSS3, будут отображать плавный эффект диагонального перехода в то время, как старые версии браузеров будут отображать более простой вариант без анимации.

HTML-код

Как обычно, первое, что нам нужно сделать, это проработать наш HTML-код для документа:

Index.html

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8"/>
<title>Smooth Diagonal Fade Gallery with CSS3 Transitions</title>

<!-- The Swipebox plugin -->
<link href="assets/swipebox/swipebox.css" rel="stylesheet" />

<!-- The main CSS file -->
<link href="assets/css/style.css" rel="stylesheet" />

<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>

<body>

<div id="loading"></div>

<div id="gallery"></div>

<!-- javascript Includes -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<script src="assets/swipebox/jquery.swipebox.min.js"></script>
<script src="assets/js/jquery.loadImage.js"></script>
<script src="assets/js/script.js"></script>

</body>
</html>

Галерея работает при помощи библиотеки jQuery, которую мы включаем перед закрывающим тегом body. Мы также воспользовались великолепным небольшим плагином лайтбокса под названием Swipebox, но вы можете без труда заменить его другим плагином по вашему усмотрению. Два основных div-элемента: #loading и #gallery. Первый содержит gif-анимацию с индикатором загрузки в то время, как второй отображает фотографии из галереи. Div-элемент #gallery обозначен свойством position:fixed, и поэтому занимает все окно браузера. Верстка для самих фотографий довольно проста:

<a href="assets/photos/large/34.jpg" class="swipebox static"
style="width:148px;height:129px;background-image:url(assets/photos/thumbs/34.jpg)">
</a>

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

Галерея с плавными диагональными переходами на CSS3

Сканирование фотографий при помощи PHP

Фотографии содержатся в двух папках на сервере - assets/photos/thumbs/ для миниатюр, и assets/photos/large/ для оригинальных изображений. При помощи PHP мы сканируем папки и выдаем JSON с названиями файлов. С другой стороны, вы можете извлечь изображения из базы данных, но вам придется сохранять ту же структуру. Взгляните на скрипт:

Load.php

// Scan all the photos in the folder
$files = glob('assets/photos/large/*.jpg');

$data = array();
foreach($files as $f){
$data[] = array(
'thumb' => str_replace('large', 'thumbs', $f),
'large' => $f
);
}

// Duplicate the photos a few times, so that we have what to paginate in the demo.
// You most certainly wouldn't want to do this with your real photos.
// $data = array_merge($data, $data);
// $data = array_merge($data, $data);
// $data = array_merge($data, $data);

header('Content-type: application/json');

echo json_encode(array(
'data' => $data,
));

Добавлять новые изображения в галерею довольно просто – вам просто нужно скопировать изображение и миниатюру (у них должны быть одинаковые названия). Мы скопировали изображения несколько раз, чтобы наша галерея немного заполнилась, но вам вероятно следует проделать эту операцию с разными изображениями.

Теперь, когда мы разобрались с JSON, давайте приступим к написанию javascript-кода!

javascript-код

Вот что нам нужно сделать:

* Сначала мы запустим GET-запрос AJAX, чтобы извлечь все фотографии на диске из PHP-скрипта.
* Затем мы подсчитаем, сколько фотографий нужно отображать на странице и их размер в зависимости от габаритов окна, чтобы они идеально выстроились в сетку.
* Мы предварительно подгрузим изображения, которые должны быть отображены на текущей странице при помощи скрипта предварительной загрузки, который использует jQuery deferreds. Тем временем будет отображаться div #loading.
* После того, как все будет загружено, мы сгенерируем верстку для фотографий и добавим их в элемент #gallery. Затем мы запустим диагональную анимацию и инициализируем галерею Swipebox.
* Когда пользователь кликает по ссылке, мы повторяем этапы 3 и 4 (с анимацией либо от верхнего левого угла, либо от правого нижнего).

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

assets/js/script.js

$(function(){

// Global variables that hold state

var page = 0,
per_page = 100,
photo_default_size = 150,
picture_width = photo_default_size,
picture_height = photo_default_size,
max_w_photos, max_h_photos
data = [];

// Global variables that cache selectors

var win = $(window),
loading = $('#loading'),
gallery = $('#gallery');

gallery.on('data-ready window-resized page-turned', function(event, direction){

// Here we will have the javascript that preloads the images
// and adds them to the gallery

});

// Fetch all the available images with
// a GET AJAX request on load

$.get('load.php', function(response){

// response.data holds the photos

data = response.data;

// Trigger our custom data-ready event
gallery.trigger('data-ready');

});

gallery.on('loading',function(){
// show the preloader
loading.show();
});

gallery.on('loading-finished',function(){
// hide the preloader
loading.hide();
});

gallery.on('click', '.next', function(){
page++;
gallery.trigger('page-turned',['br']);
});

gallery.on('click', '.prev', function(){
page--;
gallery.trigger('page-turned',['tl']);
});

win.on('resize', function(e){

// Here we will monitor the resizing of the window
// and will recalculate how many pictures we can show
// at once and what their sizes should be so they fit perfectly

}).resize();

/* Animation functions */

function show_photos_static(){

// This function will show the images without any animations
}

function show_photos_with_animation_tl(){

// This one will animate the images from the top-left

}

function show_photos_with_animation_br(){

// This one will animate the images from the bottom-right

}

/* Helper functions */

function get_per_page(){

// Here we will calculate how many pictures
// should be shown on current page

}

function get_page_start(p){

// This function will tell us which is the first
// photo that we will have to show on the given page

}

function is_next_page(){

// Should we show the next arrow?

}

function is_prev_page(){

// Should we show the previous arrow?

}

});

Некоторые из определений функций остаются пустыми, но вы можете видеть их дальше на странице. Первая группа определенных переменных будет содержать в себе состояние галереи: размеры, массив изображений, текущую страницу и так далее, - что позволяет нам более четко разграничить логику и данные. Мы воспользуемся кастомными событиями для лучшей организации кода (за счет прослушивания и запуска случайно названных событий). Вы можете расценивать этих слушателей событий как методы объекта, а переменные в самом начале как параметры.

После того, как вы ознакомитесь со всеми комментариями в вышеприведенном фрагменте кода, продолжите работу с первым слушателем событий, который выдает необходимую порцию массива изображения в зависимости от текущей страницы:

gallery.on('data-ready window-resized page-turned', function(event, direction){

var cache = [],
deferreds = [];

gallery.trigger('loading');

// The photos that we should be showing on the new screen
var set = data.slice(get_page_start(), get_page_start() + get_per_page());

$.each(set, function(){

// Create a deferred for each image, so
// we know when they are all loaded
deferreds.push($.loadImage(this.thumb));

// build the cache
cache.push('<a href="' + this.large + '" class="swipebox"' +
'style="width:' + picture_width + 'px;height:' + picture_height + 'px;background-image:url(' + this.thumb + ')">'+
'</a>');
});

if(is_prev_page()){
cache.unshift('<a class="prev" style="width:' + picture_width + 'px;height:' + picture_height + 'px;"></a>');
}

if(is_next_page()){
cache.push('<a class="next" style="width:' + picture_width + 'px;height:' + picture_height + 'px;"></a>');
}

if(!cache.length){
// There aren't any images
return false;
}

// Call the $.when() function using apply, so that
// the deferreds array is passed as individual arguments.
// $.when(arg1, arg2) is the same as $.when.apply($, [arg1, arg2])

$.when.apply($, deferreds).always(function(){

// All images have been loaded!

if(event.type == 'window-resized'){

// No need to animate the photos
// if this is a resize event

gallery.html(cache.join(''));
show_photos_static();

// Re-initialize the swipebox
$('#gallery .swipebox').swipebox();

}
else{

// Create a fade out effect
gallery.fadeOut(function(){

// Add the photos to the gallery
gallery.html(cache.join(''));

if(event.type == 'page-turned' && direction == 'br'){
show_photos_with_animation_br();
}
else{
show_photos_with_animation_tl();
}

// Re-initialize the swipebox
$('#gallery .swipebox').swipebox();

gallery.show();

});
}

gallery.trigger('loading-finished');
});

});

Несмотря на то, что изображения добавляются в div #gallery в рамках одной операции, посредством CSS и выставляется свойство opacity:0. Это дает основу для функций анимации. Первая из них отображает фотографии без анимации, а последние две анимируют их, применяя эффект волны с верхнего левого или правого нижнего края. Анимация полностью основана на CSS, и запускается тогда, когда мы задаем изображению имя класса посредством jQuery.

function show_photos_static(){

// Show the images without any animations
gallery.find('a').addClass('static');

}

function show_photos_with_animation_tl(){

// Animate the images from the top-left

var photos = gallery.find('a');

for(var i=0; i<max_w_photos + max_h_photos; i++){

var j = i;

// Loop through all the lines
for(var l = 0; l < max_h_photos; l++){

// If the photo is not of the current line, stop.
if(j < l*max_w_photos) break;

// Schedule a timeout. It is wrapped in an anonymous
// function to preserve the value of the j variable

(function(j){
setTimeout(function(){
photos.eq(j).addClass('show');
}, i*50);
})(j);

// Increment the counter so it points to the photo
// to the left on the line below

j += max_w_photos - 1;
}
}
}

function show_photos_with_animation_br(){

// Animate the images from the bottom-right

var photos = gallery.find('a');

for(var i=0; i<max_w_photos + max_h_photos; i++){

var j = per_page - i;

// Loop through all the lines
for(var l = max_h_photos-1; l >= 0; l--){

// If the photo is not of the current line, stop.
if(j > (l+1)*max_w_photos-1) break;

// Schedule a timeout. It is wrapped in an anonymous
// function to preserve the value of the j variable

(function(j){
setTimeout(function(){
photos.eq(j).addClass('show');
}, i*50);
})(j);

// Decrement the counter so it points to the photo
// to the right on the line above

j -= max_w_photos - 1;
}
}
}

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

win.on('resize', function(e){

var width = win.width(),
height = win.height(),
gallery_width, gallery_height,
difference;

// How many photos can we fit on one line?
max_w_photos = Math.ceil(width/photo_default_size);

// Difference holds how much we should shrink each of the photos
difference = (max_w_photos * photo_default_size - width) / max_w_photos;

// Set the global width variable of the pictures.
picture_width = Math.ceil(photo_default_size - difference);

// Set the gallery width
gallery_width = max_w_photos * picture_width;

// Let's do the same with the height:

max_h_photos = Math.ceil(height/photo_default_size);
difference = (max_h_photos * photo_default_size - height) / max_h_photos;
picture_height = Math.ceil(photo_default_size - difference);
gallery_height = max_h_photos * picture_height;

// How many photos to show per page?
per_page = max_w_photos*max_h_photos;

// Resize the gallery holder
gallery.width(gallery_width).height(gallery_height);

gallery.trigger('window-resized');

}).resize();

Последняя строка предназначена для того, чтобы функция запускалась сразу после определения, что означает, что мы корректируем значения с самого начала.

Следующие вспомогательные функции берут на себя большинство часто используемых вычислений:

function get_per_page(){

// How many pictures should be shown on current page

// The first page has only one arrow,
// so we decrease the per_page argument with 1
if(page == 0){
return per_page - 1;
}

// Is this the last page?
if(get_page_start() + per_page - 1 > data.length - 1){
// It also has 1 arrow.
return per_page - 1;
}

// The other pages have two arrows.
return per_page - 2;
}

function get_page_start(p){

// Which position holds the first photo
// that is to be shown on the give page

if(p === undefined){
p = page;
}

if(p == 0){
return 0;
}

// (per_page - 2) because the arrows take up two places for photos
// + 1 at the end because the first page has only a next arrow.

return (per_page - 2)*p + 1;
}

function is_next_page(){

// Should we show the next arrow?

return data.length > get_page_start(page + 1);
}

function is_prev_page(){

// Should we show the previous arrow?

return page > 0;
}

Здесь может быть всего несколько строк, и использоваться они могут всего лишь единожды или дважды, но они делают огромную работу для того, чтобы код был максимально читаемым.

Галерея с плавными диагональными переходами на CSS3

CSS-код

И наконец, мы добрались до CSS-кода. По умолчанию у изображений выставлено нулевое значение непрозрачности, и к ним применяется scale-трансформация до 0.8. Мы также используем параметр transition, который анимирует каждое изменение данного атрибута. Класс .show, который добавляется к функциям анимации, повышает уровень непрозрачности и scale элемента, что автоматически анимируется браузером.

assets/css/styles.css

#gallery{
position:fixed;
top:0;
left:0;
width:100%;
height:100%;
}

#gallery a{
opacity:0;
float:left;
background-size:cover;
background-position: center center;

-webkit-transform:scale(0.8);
-moz-transform:scale(0.8);
transform:scale(0.8);

-webkit-transition:0.4s;
-moz-transition:0.4s;
transition:0.4s;
}

#gallery a.static:hover,
#gallery a.show:hover{
opacity:0.9 !important;
}

#gallery a.static{
opacity:1;

-webkit-transform:none;
-moz-transform:none;
transform:none;

-webkit-transition:opacity 0.4s;
-moz-transition:opacity 0.4s;
transition:opacity 0.4s;
}

#gallery a.next,
#gallery a.prev{
background-color:#333;
cursor:pointer;
}

#gallery a.next{
background-image:url('../img/arrow_next.jpg');
}

#gallery a.prev{
background-image:url('../img/arrow_prev.jpg');
}

#gallery a.show{
opacity:1;

-webkit-transform:scale(1);
-moz-transform:scale(1);
transform:scale(1);
}

Класс .static устанавливается посредством функции the show_photos_static(), и нужен он для отключения всех анимаций (за исключением opacity, так как нам нужно, чтобы эффект при наведении был плавным), и мгновенно отображает фотографии (в противном случае, при каждом изменении размера окна вы будете наблюдать диагональный эффект затемнения). Остальную часть этого файла вы можете скачать в файлах к руководству, которые можно скачать в самом верху страницы!

Мы закончили!

Надеемся, что вам понравится этот небольшой эксперимент, и вы сможете найти применение данного эффекта в своих будущих проектах.
Обнаружили ошибку или мёртвую ссылку?
Выделите проблемный фрагмент мышкой и нажмите CTRL+ENTER.
В появившемся окне опишите проблему и отправьте уведомление Администрации ресурса.
Нужна органическая вечная ссылка из данной статьи? Постовой?
Подробности здесь
Вам понравился материал? Поблагодарить легко!
Будем весьма признательны, если поделитесь этой статьей в социальных сетях:

Ключевые тэги: CSS, фотография, PHP, JSON
Опубликовал Design FactoRy   Прочитано (раз): 5747   |   Нет комментариев
Автор перевода — CoolWebmasters.Com ©   |   Источник материала / оригинал статьи   Распечатать
Другие статьи и новости по теме:
Добавление комментария
Уважаемые пользователи!
При добавлении комментариев на сайт Вам следует учитывать следующее - все комментарии проверяются Администрацией на предмет отсутствия спама. При обнаружении признаков спама, в оставленном Вами комментарии, сам комментарий будет незамедлительно удалён, а Ваш IP-адрес будет забанен без предупреждения! Учётные записи пользователей, рассылающих спам, блокируются/удаляются без права последующего восстановления.

С уважением, Администрация сайта.
* = поля обязательны к заполнению
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Вопрос : Назовите месяц October по-русски
Подтверждение кода безопасности :

Включите эту картинку для отображения кода безопасности
обновить, если не виден код


Популярные публикации


















Свежие шаблоны сайтов каждый день
С миру по нитке
«    Ноябрь 2017    »
ПнВтСрЧтПтСбВс
 12345
6789101112
13141516171819
20212223242526
27282930