1. Web Design
  2. HTML/CSS

Оживляем наше порфтфолио Behance при помощи анимаций CSS

В предыдущих руководствах мы разобрались с тем, как использовать API Behance для обеспечения работы нашей собственной веб-страницы, и затем при помощи LESS мы сделали так, чтобы все это выглядело прилично. В данном руководстве мы улучшим удобство использования нашей веб-страницы для пользователей за счет добавления модального окна (* в графическом интерфейсе пользователя (GUI) - дочернее окно (child window) для взаимодействия пользователя с приложением: оно служит для получения информации от приложения или для ввода запрашиваемых данных и выбора опций; поэтому модальное окно часто называется диалоговым. Если открывается модальное окно, то возврат управления приложению может произойти только после реакции пользователя)) и некоторых анимаций CSS.
Scroll to top
This post is part of a series called Build Your Own Behance-Powered Portfolio.
Styling Our Behance Portfolio Website Using LESS

Russian (Pусский) translation by AlexBioJS (you can also view the original English article)

В предыдущих руководствах мы разобрались с тем, как использовать API Behance для обеспечения работы нашей собственной веб-страницы, и затем при помощи LESS мы сделали так, чтобы все это выглядело прилично. В данном руководстве мы улучшим удобство использования нашей веб-страницы для пользователей за счет добавления модального окна (* в графическом интерфейсе пользователя (GUI) - дочернее окно (child window) для взаимодействия пользователя с приложением: оно служит для получения информации от приложения или для ввода запрашиваемых данных и выбора опций; поэтому модальное окно часто называется диалоговым. Если открывается модальное окно, то возврат управления приложению может произойти только после реакции пользователя)) и некоторых анимаций CSS.

Добавление эффектов модального окна и анимаций

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

Ниже приведены инструменты, необходимые нам для реализации вышеуказанного:

Magnific Popup

Мы воспользуемся плагином jQuery под названием Magnific Popup, разработанным Дмитрием Семеновым. Он небольшого размера, быстро работает и соответствует требованиям отзывчивого веб-дизайна – как раз то, что нам необходимо.

Animate.css

Также мы добавим анимации CSS, что поможет нам оживить наш веб-сайт. Мы воспользуемся несколькими фрагментами библиотеки Animate.css, которая предоставляет огромную коллекцию анимаций CSS3, которыми вы можете воспользоваться путем добавления определенных классов для немедленного применения анимаций.

Добавляем Magnific Popup

Давайте начнем с добавления таблицы стилей Magnific Popup в теге head.

1
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.min.css">
2
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/0.9.9/magnific-popup.css">
3
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.min.css">
4
<link href='http://fonts.googleapis.com/css?family=Cantata+One|Open+Sans:300,600' rel='stylesheet' type='text/css'>
5
<link rel="stylesheet" href="css/style.css">

Затем мы добавим скрипты в самом низу страницы, благодаря чему у DOM (* Document Object Model – объектная модель документа) будет время загрузиться до загрузки скриптов, меняющих поведение элементов.

1
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
2
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.min.js"></script>
3
<script src="//cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/0.9.9/jquery.magnific-popup.min.js"></script>

Далее нам необходимо будет добавить атрибут HTML5 data, data-project-id="{{this.id}}", к элементу figure, который оборачивает изображение с эскизом проекта портфолио, следующим образом:

1
...
2
<figure class="portfolio-cover" title="{{this.name}}" data-project-id="{{this.id}}">
3
  {{#if this.covers.[404]}}
4
	<img class="portfolio-image" src="{{this.covers.[404]}}" alt="">
5
	{{else}}
6
		{{#if this.covers.[230]}}
7
		<img class="portfolio-image" src="{{this.covers.[230]}}" alt="">
8
		{{else}}
9
		<img class="portfolio-image" src="{{this.covers.[202]}}" alt="">
10
		{{/if}}
11
	{{/if}}
12
</figure>
13
...

Обновите страницу и проинспектируйте веб-сайт при помощи Chrome DevTools или Firebug. Вы должны будете обнаружить, что data-project-id содержит ID проекта портфолио, как показано ниже:

Атрибут data-project-id элемента figure с ID

Мы воспользуемся атрибутом data для получения контента выбранного проекта портфолио с присвоенным ему ID позже.

После этого нам также нужно будет изменить вид курсора на курсор в виде линзы с плюсиком следующим образом:

1
 ...
2
.portfolio-cover {
3
 	cursor: pointer;
4
 	cursor: -webkit-zoom-in;
5
 	cursor: -moz-zoom-in;
6
 	cursor: zoom-in;
7
 	width: 100%;
8
}
9
...

Благодаря нему пользователю будет дана подсказка, что для изображения имеется возможность увеличения; пользователи должны полагать, что могут нажать по изображению. Однако согласно MDN (* Mozilla Developer Network) значение zoom-in еще не поддерживается ни в какой версии Internet Explorer.Mozilla Developer Network Поэтому мы также указали в качестве значения cursor значение pointer (* курсор-рука – используется для сообщения пользователю, что под ним находится гиперссылка) перед cursor: zoom-in в качестве запасного варианта для Internet Explorer и других браузеров, в которых, возможно, нет поддержки cursor: zoom-in.

Запускаем Magnific Popup

Теперь мы добавим скрипт для инициализации Magnific Popup. Поскольку нашей целью является не только показ изображения с эскизом проекта портфолио, но и остальных изображений проекта, скрипт, вероятно, будет выглядеть слегка объемным. Поэтому мы будем добавлять его код постепенно. Первое, что мы напишем – метод .on('click') jQuery. Magnific Popup будет запускаться только при нажатии пользователем по изображению с эскизом.

1
$('#portfolio').on('click', '.portfolio-cover', function() {
2
	//the rest of the script goes here...

3
}

Далее мы определим следующие переменные:

  • переменная $this содержит ссылку на объект, к которому прицеплен метод .on().
  • в projectID будет содержаться результат, возвращаемый методом $this.data('project-id'), при помощи которого извлекается ID выбранного проекта из атрибута data-project-id. Мы будем его использовать для получение контента при помощи API Behance.
  • в beProjectContentAPI будет содержаться конечная точка (* отдельная функция API) API Behance для получения контента проекта Behance.
  • в keyName будет находиться ключевое имя, которое мы будем использовать для сохранения данных, полученных с Behance, в localStorage. Формат имени будет следующим: behanceProjectImages-, за которым следует ID проекта. В противоположность тому, что мы делали ранее, теперь мы используем localStorage для сохранения данных, а не sessionStorage. Это так, поскольку мы предполагаем, что пользователи Behance редко бы обновляли контент после его опубликования. Так что в данном случае нам лучше использовать localStorage, поскольку в нем данные будут сберегаться постоянно; данные будут оставаться в браузере до тех пор, пока мы их целенаправленно не удалим.
1
$('#portfolio').on('click', '.portfolio-cover', function() {
2
	var $this = $(this),
3
	projectID = $this.data('project-id'),
4
	beProjectContentAPI = 'http://www.behance.net/v2/projects/'+ projectID +'?callback=?&api_key=' + apiKey,
5
	keyName = 'behanceProjectImages-' + projectID;
6
}

Затем мы создаем главную функцию, при помощи которой будет запущен код Maginific Popup. Мы назовем ее showGallery(). Также мы применим следующие опции для Magnific Popup:

  • items; эта опция очень важна. В этом свойстве будет содержаться список изображений, которые будут отображаться в модальном окне.
  • gallery; при активации этой опции будут добавлены стрелки для просмотра содержащихся в проекте изображений.
  • type; в качестве типа контента, который разрешено использовать в модальном окне, мы будем использовать изображение.

Последний фрагмент кода неизбежен; нам необходимо будет добавить .magnificPopup('open'), чтобы за счет него немедленно было открыто модальное окно после инициализации.

1
$('#portfolio').on('click', '.portfolio-cover', function() {
2
	var $this =	$(this),
3
		projectID = $this.data('project-id'),
4
		beProjectContentAPI = 'http://www.behance.net/v2/projects/'+ projectID +'?callback=?&api_key=' + apiKey,
5
		keyName = 'behanceProjectImages-' + projectID;
6
	
7
	function showGallery(dataSource) {	
8
		$this.magnificPopup({
9
			items: dataSource,
10
			gallery: {
11
				enabled: true
12
			},
13
			type: 'image'
14
		}).magnificPopup('open');
15
	};
16
}

Мы будем запускать showGallery() только при определенных условиях; если данные для выбранного проекта портфолио доступны в localStorage, то необходимо будет получить их и выполнить showGallery(), в ином случае нужно получить для начала данные через API при помощи $.getJSON(), затем выполнить showGallery() и сохранить эти данные в localStorage для дальнейшего использования. Как и ранее, нам необходимо воспользоваться JSON.stringify() для преобразования данных в строку, благодаря чему их можно будет сохранить в localStorage, а затем мы воспользуемся JSON.parse() для преобразования их обратно в объект JSON.

Проверяем, что пришедший контент – изображения

Здесь следует отметить, что в качестве поступающего через API контента может быть видео, встроенное видео или текст, которые нам не подходят; нам нужны только изображения. Поэтому перед отправлением данных в localStorage нам необходимо добавить следующий фрагмент кода для фильтрации контента:

1
var src = [];
2
$.each(projectContent.project.modules, function(index, mod) {
3
	if(mod.src != undefined) {
4
		src.push({ src: mod.src });	
5
	}
6
});

Ниже приводится финальный код всего скрипта:

1
$('#portfolio').on('click', '.portfolio-cover', function() {
2
	var $this =	$(this),
3
		projectID = $this.data('project-id'),
4
		beProjectContentAPI = 'http://www.behance.net/v2/projects/'+ projectID +'?callback=?&api_key=' + apiKey,
5
		keyName = 'behanceProjectImages-' + projectID;
6
	
7
	function showGallery(dataSource) {	
8
		$this.magnificPopup({
9
			items: dataSource,
10
			gallery: {
11
				enabled: true
12
			},
13
			type: 'image'
14
		}).magnificPopup('open');
15
	};
16
17
	if(localStorage.getItem(keyName)) {
18
		var srcItems = JSON.parse(localStorage.getItem(keyName));
19
		showGallery(srcItems);
20
	} else {
21
		$.getJSON(beProjectContentAPI, function(projectContent) {
22
			var src = [];
23
			$.each(projectContent.project.modules, function(index, mod) {
24
				if(mod.src != undefined) {
25
					src.push({ src: mod.src });	
26
				}
27
			});
28
			showGallery(src);
29
			var data = JSON.stringify(src);
30
			localStorage.setItem(keyName, data);
31
		});
32
	};
33
});

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

Если вы проинспектируете веб-сайт при помощи Chrome DevTools, вы должны будете обнаружить, что контент хранится в localStorage.

К тому же вы можете просмотреть все изображения контента проекта при помощи стрелок. Однако переход между изображениями сейчас происходит довольно неудобно (верно?); мы переходим от одного изображения к другому мгновенно. Так что давайте сделаем его более плавным при помощи анимаций, хорошо?

Добавляем Animate.css

Для начала нам необходимо будет добавить mainClass: 'animated' и removalDelay: 350 в нашу функцию magnificPopup.

1
 ... 
2
function showGallery(dataSource) {	
3
	$this.magnificPopup({
4
		items: dataSource,
5
		gallery: {
6
			enabled: true
7
		},
8
		type: 'image',
9
		mainClass: 'animated',
10
		removalDelay: 350
11
	}).magnificPopup('open');
12
};
13
...

В этом коде мы добавили новый класс под названием animated к нашему модальному окну. Класс animated используется в Animate.css для назначения анимации какому-то элементу. Этот класс также мог бы быть полезен для активации или отключения анимации, когда вам это необходимо; если вы хотите отключить ее, то просто удалите строку с mainClass: 'animated'.

Также мы добавили removalDelay, при помощи которого указывается время, которое пройдет до того, как модальное окно будет полностью удалено из DOM. За счет этой задержки у пользователя будет возможность заметить анимацию.

Подгоняем стилевое оформление для ключевых кадров

Далее мы настроим несколько ключевых кадров (* кадр, создаваемый при изменении атрибута, чтобы зафиксировать его новое состояние, например, начало или конец нужной траектории перемещения, смену материала и т. п.) CSS,  переходов и трансформаций, за счет которых создается эффект анимации при помощи Animate.css. Мы сконвертируем их код CSS в формат LESS, используя LESSHat.

Давайте начнем с ключевых кадров.

1
.keyframes(~'fadeInRight, 0% { transform: translateX(20px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; }');
2
.keyframes(~'fadeInLeft, 0% { transform: translateX(-20px); opacity: 0; } 100% { transform: translateX(0); opacity: 1; }');
3
4
.keyframes(~'fadeOutRight, 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(20px); opacity: 0; }');
5
.keyframes(~'fadeOutLeft, 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(-20px); opacity: 0; }');
6
7
.keyframes(~'fadeInDown, 0% { transform: translateY(-20px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; }');
8
.keyframes(~'fadeOutDown, 0% { transform: translateY(0); opacity: 1; } 100% { transform: translateY(20px); opacity: 0; }');

Мы добавили несколько ключевых кадров под названиями fadeInRight, fadeInLeft, fadeOutRight, fadeOutLeft, fadeInDown и fadeOutDown, код которых был преобразован в код формата LESS при помощи миксинов .keyframes() LESSHat.

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

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

1
.mfp-bg.animated {
2
    opacity: 0;
3
    .transition(opacity 350ms ease-out);
4
}
5
.mfp-bg.mfp-ready.animated {
6
    opacity: 0.8;
7
}
8
.mfp-bg.mfp-removing.animated {
9
    opacity: 0;
10
}

В Magnific Popup для верхнего слоя фона задан класс под названием mfp-bg. В вышеуказанном коде мы устанавливаем в качестве значения его прозрачности 0, так что изначально фон будет невидимым, а также задаем продолжительность перехода для свойства opacity.

Кроме этого за счет Magnific Popup будет добавлен набор новых классов для определения поведения элемента при наступлении различных состояний; например при полном появлении модального окна будет добавлен класс mfp-ready. Для этого состояния мы указали в качестве значения прозрачности 0.8. Поскольку мы установили значение для перехода, то в результат получится эффект анимации; прозрачность будет изменяться от 0 до 0.8 за 350 ms.

Затем после исчезновения модального окна при помощи Magnific Popup будет добавлен класс mfp-removing. Для этого состояния мы изменяем значение прозрачности обратно (0), благодаря чему верхний слой фона снова становится невидимым.

Ниже приводятся стилевые правила для реализации анимации контента модального окна.

1
.mfp-wrap.animated .mfp-content {
2
    .animation-duration(350ms);
3
}
4
.mfp-wrap.animated .mfp-content {
5
    .animation-name(fadeInDown);
6
}
7
.mfp-wrap.mfp-removing.animated .mfp-content {
8
    .animation-name(fadeOutDown);
9
}

Как и в случае с верхним слоем фона, мы также задали для контента в качестве значения продолжительности перехода 350 ms. Также мы применяем ключевые кадры при помощи миксина .animation-name(). За счет этого кода контент будет при показе постепенно появляться и в тоже время опускаться сверху, а затем при исчезновении опускаться вниз и постепенно пропадать.

Анимация стрелок для перехода между изображениями

Наконец, мы добавим анимацию для стрелок

1
.mfp-wrap.animated .mfp-arrow {
2
    .animation-duration(350ms);
3
}
4
.mfp-wrap.animated .mfp-arrow-left {
5
    .animation-name(fadeInRight);
6
}
7
.mfp-wrap.mfp-removing.animated .mfp-arrow-left {
8
    .animation-name(fadeOutLeft);
9
}
10
.mfp-wrap.animated .mfp-arrow-right {
11
    .animation-name(fadeInLeft);
12
}
13
.mfp-wrap.mfp-removing.animated .mfp-arrow-right {
14
    .animation-name(fadeOutRight);
15
}

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

Заключение

Это была очень длинная серия руководств! Мы успешно создали рабочий вебсайт с персональным портфолио с нуля, используя в качестве источника данных API Behance. Для того чтобы его создать, мы также воспользовались рядом современных инструментов вроде LESS, HandlebarsJS и Animate.css. Этот веб-сайт довольно легко закачать на сервер, поскольку он состоит всего лишь из одной статической HTML-страницы – и вправду, демоверсия нашего сайта располагается на сервере GitHub в качестве статической страницы. Также вы можете закачать ее на веб-сервер при помощи FTP.

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