Advertisement
  1. Code
  2. Web Development

Создаем навигационную панель с крутой анимацией при помощи CSS и jQuery

Scroll to top
Read Time: 15 min

() translation by (you can also view the original English article)

Анимация и визуальная обратная связь – отличные способы содействия пользователю при навигации и взаимодействии с веб-сайтом. Хотя обычно Adobe Flash (* мультимедийная программная платформа компании Adobe Systems для создания веб-приложений, рекламных баннеров, анимации, игр, десктопных приложений и также для воспроизведения на веб-страницах видео- и аудиозаписей. В июле 2017 года Adobe признала технологию Flash устаревшей, её жизненный цикл будет завершён в конце 2020 года, когда Adobe прекратит поддержку и распространение Flash. Здесь и далее примеч. пер.) отвечала за анимирование чего угодно, в наши дни за счет потрясающих возможностей JavaScript мы можем обойтись вообще без Flash. Сегодня мы создадим навигационное меню с очень крутой анимацией при помощи CSS и jQuery.

Демоверсия и исходный код


Краткий обзор

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

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

  • Создание эскиза
  • Создание ресурсов
  • Написание кода HTML
  • Написание кода CSS
  • Создание анимации при помощи jQuery

Шаг 1: Эскиз

Для начала давайте взглянем, что нам необходимо тут реализовать.

Итак, вот примерное представление того, что нам необходимо будет сделать:

  • Поделить страницу на четыре части: header (* с заголовком), navigation (* с навигационным меню), content header (* для размещения заголовка контента) и rest of content (* остальная часть контента).
  • Область для заголовка представить простым контейнером <div>.
  • Область с навигационным меню поделить на несколько контейнеров <div>, соответствующих элементам меню.
  • Теперь вот что: в основном мы используем контейнер <ul><li>, однако поскольку каждый элемент меню уникален,
    то я не вижу выгоды от использования <ul><li>, так что я буду использовать вместо него контейнер .

  • Контент представить простым контейнером <div>.

Подводя итог, получаем следующее:

1
<!-- header section-->
2
<div id="header"></div>
3
4
<!-- navigation section-->  	
5
<div id="navigation" class="container">
6
	<div><a href="#">home</a></div>
7
	<div><a href="#">about</a></div>
8
	<div><a href="#">services</a></div>
9
	<div><a href="#">solutions</a></div>
10
	<div><a href="#">contact</a></div>
11
</div>
12
13
<!-- container section-->
14
<div class="container">
15
	<div id="content-title"></div>
16
	<!-- rest of the content -->
17
</div>

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

Шаг 2: Ресурсы

Я предполагаю, что у вас имеются базовые представления о том, как обращаться с Photoshop, поэтому я не предоставлю вам исчерпывающих инструкций по созданию ресурсов.
Нам необходимо создать следующие ресурсы:

  • Фон для заголовка
  • Часть для размещения заголовка контента
  • Навигационное меню
  • Фон с полосками

Обратите внимание, что если вы хотите пропустить этот этап, то можете скачать архив со всеми файлами в конце руководства и извлечь мои копии!

Что ж, давайте создадим фон для заголовка. Откройте Photoshop и создайте полотно размером 1x181 px, или же вы можете создать полотно более крупных размеров и затем обрезать изображение.
Создайте слой и задайте для него линейный градиент с предустановленными значениями начального и конечного цветов (Foreground to Background) протяженностью 171px, это будет основной градиент.
Создайте еще один слой и задайте для него линейный градиент с предустановленными значениями начального и конечного цветов (* конечный отсутствует; прозрачность) (Foreground to Transparent) протяженностью 10px внизу первого слоя для придания определенного эффекта затенения.

Вот как этот фон должен выглядеть, тут его размер 100x181 px, который я позже сокращу до 1x181 px.

Сохраните это изображение как 'hdr-bkg.png' в нашей папке 'img'.

Далее мы создадим часть для размещения заголовка контента. Снова откройте Photoshop и создайте полотно размером 934x284 px.
Создайте при помощи соответствующего инструмента прямоугольник со скругленными уголками, выберите созданную фигуру, создайте новый слой, добавьте градиент и добавьте падающую тень (* тень, отбрасываемая объектом).
После этого у нас получится следующее:

Сохраните это изображение как 'content-title.png' в папке 'img'.

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

Реализовать белый прямоугольник просто. Нужно всего лишь создать прямоугольник со скругленными уголками размером 98px x 58px и окрасить его в белый цвет. Убедитесь, что фон прозрачен.

Сохраните это изображение как 'white.jpg' в папке 'img'.

Переходим к реализации элемента навигационного меню. Откройте Photoshop и создайте документ размером 490px x 58px.
Создайте прямоугольник со скругленными уголками размером около 98px x 58px и разместите в нем какой-то текст. Нам будут необходимы две копии каждого текста.
Я добавил небольшую падающую тень для каждого текста, но это, естественно, на любителя. Вы можете использовать для элементов собственные цвета.

Теперь просто продублируйте этот слой вдоль горизонтальной линии. Примените различные цвета и текст.

Сохраните это изображение как 'nav.jpg' в папке 'img'.

Наконец, для реализации фона с полосками я просто воспользовался онлайн-инструментом под названием Stripe Generator. Конечный результат выглядит следующим образом:

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

Шаг 3: код HTML

Теперь давайте бегло набросаем наш HTML-код.

1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
<html xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
	<title>slick animated menu</title>
5
  	<!--our CSS file-->
6
	<link rel="stylesheet" href="css/main.css" type="text/css" />
7
	<!--jQuery library-->
8
	<script type="text/javascript" src="js/jquery.js" ></script>
9
	<!--jQuery plugin, we’ll get to this later-->
10
	<script type="text/javascript" src="js/jquery-bp.js" ></script>
11
	<!--Our animation script-->
12
	<script type="text/javascript" src="js/navigation.js" ></script>
13
</head>
14
<body>
15
	<div id="header"></div>
16
	<div id="navigation" class="container">
17
		<div id="home"><a href="home">home</a></div>
18
		<div id="about"><a href="about">about</a></div>
19
		<div id="services"><a href="services">services</a></div>
20
		<div id="solutions"><a href="solutions">solutions</a></div>
21
		<div id="contact"><a href="contact">contact</a></div>
22
	</div>
23
	<div class="container">
24
		<div class="content">
25
			<div id="content-title"></div>
26
			<!-- the rest of the content-->
27
		</div>
28
	</div>
29
</body>

Этот вполне соответствует тому плану действий, что набросали в Шаге 1.

Я добавил ссылку на файл 'main.css', который нам еще предстоит создать,
и также добавил некоторые ссылки на кое-какие файлы JavaScript. Поскольку каждый элемент навигационного меню уникален, то я добавил им ID.
Нам нужно будет еще добавить определенное стилевое оформление, применяемое для каждого элемента меню, за счет этого нам будет проще изменять стилевое оформление в дальнейшем.

У нас также будет появляться белый прямоугольник сверху каждого элемента навигационного меню при перемещении курсора поверх меню или при выборе элемента меню, так что нам понадобится еще один контейнер <div> для него. Финальный код HTML будет выглядеть следующим образом:

1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
<html xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
	<title>slick animated menu</title>
5
  
6
	<link rel="stylesheet" href="css/main.css" type="text/css" />
7
	
8
	<script type="text/javascript" src="js/jquery.js" ></script>
9
	<script type="text/javascript" src="js/jquery-bp.js" ></script>
10
	<script type="text/javascript" src="js/navigation.js" ></script>
11
</head>
12
<body>
13
	<div id="header"></div>
14
	<div id="navigation" class="container">
15
		<div id="home" class="pri-nav"><div><a href="home">home</a></div></div>
16
		<div id="about" class="pri-nav"><div><a href="about">about</a></div></div>
17
		<div id="services" class="pri-nav"><div><a href="services">services</a></div></div>
18
		<div id="solutions" class="pri-nav"><div><a href="solutions">solutions</a></div></div>
19
		<div id="contact" class="pri-nav"><div><a href="contact">contact</a></div></div>
20
	</div>
21
	<div class="container">
22
		<div class="content">
23
			<div id="content-title"></div>
24
			<!-- the rest of the content-->
25
		</div>
26
	</div>
27
</body>

Сохраните его как 'index.html'. На данный момент в качестве HTML-страницы у нас имеется следующее:

Шаг 4: CSS

Давайте применим некоторое стилевое оформление к веб-странице. Мы начнем с задания правил для фона и части с заголовком.

1
body {
2
	background: url(../img/body-bkg.jpg) repeat scroll;
3
	margin: 0;
4
	padding: 0;
5
}
6
7
.containe r{
8
	margin: 0pt auto;
9
	width:950px;
10
}
11
#header {
12
	background: url(../img/hdr-bkg.jpg) repeat-x scroll;
13
	height:181px;
14
}

Сохраните этот код как main.css в папке 'css'.

Теперь наша страница выглядит следующим образом:

Теперь давайте добавим стилевое оформление для каждого элемента меню. Помните, что мы хотим, чтобы белый прямоугольник располагался сверху каждого элемента меню,
так что в качестве значения position устанавливаем absolute. Добавьте следующие правила в файл 'main.css'.

1
#navigation{
2
	height:60px;
3
}
4
5
#home, #home div, 
6
#about, #about div, 
7
#services , #services div, 
8
#solutions, #solutions div, 
9
#contact,  #contact div {
10
	height:80px;
11
	position:absolute;
12
	width:97px;
13
	float:left;
14
}
15
16
#home, #about, #services, #solutions, #contact{
17
	background-image: url(../img/nav.jpg);
18
	background-attachment: scroll;
19
	background-repeat: no-repeat;
20
	top:171px;
21
}
22
23
#home{
24
	background-position: 0px -25px;
25
	margin-left:6px;
26
}
27
28
#about{
29
	background-position: -98px -25px;
30
	margin-left:105px;
31
}
32
33
#services{
34
	background-position: -196px -25px;
35
	margin-left:204px;
36
}
37
38
#solutions{
39
	background-position: -294px -25px;
40
	margin-left:303px;
41
}
42
43
#contact{
44
	background-position: -392px -25px;
45
	margin-left:402px;
46
}
47
48
#home div, #about div, #services div, #solutions div, #contact div {
49
	background-image: url(../img/white.jpg);
50
	background-attachment: scroll;
51
	background-repeat: no-repeat;
52
	background-position: 0px -60px;	
53
}

Теперь у нас имеется следующее:

Имеется одна проблемка: ссылка <a href> располагается поверх каждого элемента меню; давайте удалим ее при помощи установления для свойства text-indent (* устанавливает величину отступа первой строки блока текста) огромного значения – гарантировано удаляя ссылку с экрана.
Добавьте этот код в вашу таблицу стилей.

1
.pri-nav a{
2
	display:block;
3
	text-decoration:none;
4
	text-indent:-30000px; 
5
}

Теперь навигационное меню будет выглядеть следующим образом:

У нас имеется еще одна проблемка: мы бы хотели, чтобы навигационное меню располагалось под тенью части с заголовком. Мы можем этого добиться за счет модификации нашего стилевого оформления для части с заголовком.

1
#header{
2
	background: url(../img/hdr-bkg.jpg) repeat-x scroll;
3
	height:181px;
4
	position:absolute;
5
	z-index :100; /* ensure the header is on top of navigation area */
6
	top: 0px;
7
	left:0px;
8
	width:100%;
9
}

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

Великолепно! Давайте добавим часть с контентом, так что сможем приступить к работе со скриптом для добавления анимации.

1
.content{
2
	margin-top:160px;
3
}
4
5
#content-title{
6
	background: url(../img/content.jpg) no-repeat scroll;
7
	height:323px;
8
	position:absolute;
9
	width:100%;
10
}

Шаг 5: Скрипт для добавления анимации

Для начала давайте скачаем последнюю версию скрипта jQuery и поместим ее в папку 'js'.

По существу анимация сводится к манипуляции с позиционированием фона.
К сожалению, в jQuery имеется баг в функционале, отвечающем за анимирование свойства background-position (* за счет него задается начальное положение фонового изображения, установленного с помощью свойства background-image). Но не переживайте! Alexander Farkas создал плагин, благодаря которому эта проблема разрешается.
Скачайте файл, переименуйте его на  jquery-bp.js и сохраните в папке 'js'.

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

Из-за багов в некоторых браузерах (например Firefox) вы должны устанавливать (исходное) значение свойства background-position в самом теге:
<div style="background-position: 10px 20px"></div>
– Естественно, вы также можете выполнить это и при помощи JavaScript (jQuery):
$('#background').css({backgroundPosition: '10px 20px'});

Что ж, теперь, когда вы поняли это, давайте начнем: Мы зададим значение свойства background-position для каждого элемента в начале нашего скрипта.

1
// id for each of our menu items

2
var nav  = [ '#home', '#about', '#services', '#solutions', '#contact' ];
3
$(document).ready(function(){
4
  setBkgPos();
5
});
6
7
function setBkgPos()
8
{
9
  for ( i = 0; i < nav.length; i++ ){
10
    $(nav[i]).css({backgroundPosition: i*(-98) + 'px -25px'});
11
    $(nav[i] + ' div').css({ backgroundPosition: '0px -60px'});
12
  }
13
}

Сохраните этот код как 'navigation.js' в папке 'js'.

Теперь мы добавим обработчики для трех событий для всех элементов меню. Мы можем это выполнить при помощи функции bind ().

1
$(document).ready(function(){
2
  setBkgPos();
3
4
  // bind the event to function here

5
  for ( i = 0; i < nav.length; i++ ) {
6
    $(nav[i]).bind( 'mouseover', mMouseOver );
7
    $(nav[i]).bind( 'mouseout', mMouseOut );
8
    $(nav[i]).bind( 'click', mClick );
9
  }
10
});

Каждый раз, когда пользователь перемещает курсор поверх элемента навигационного меню, будет вызвана функция 'mMouseOver' скрипта.
Когда пользователь перемещает курсор за пределы элемента навигационного меню, будет вызвана функция 'mMouseOut' скрипта.
И когда пользователь нажимает по элементу навигационного меню, то будет вызвана функция 'mClick' скрипта.

Шаг 5.1: Обработчик для события mouseover

Давайте создадим раскадровку (* последовательность эскизов (кадров) для визуального планирования сцен перед съемкой, для графического представления шагов решения задачи, выполнения сценария, описания поведения пользователя и т. д.) для анимации, выполняемой при возникновении события mouseover.

При перемещении курсора поверх элемента:

  • Изменить изображение элемента меню (на то, что со  свечением) и изменить вид курсора по умолчанию на вид «курсор-рука».
  • Поднять элемент навигационного меню немного вверх.
  • Опустить белый прямоугольник вниз.
  • Опустить белый прямоугольник и элемент навигационного меню вниз.
  • Поднять белый прямоугольник и элемент навигационного меню вверх на конечное местоположение.
  • И заменить изображение элемента меню на первоначальное.

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

1
function _getHPos( id )
2
{
3
  for ( i = 0; i < nav.length; i++ ){
4
    if ( '#' + id == nav[i] ){
5
      return i*(-98);
6
    }
7
  }	
8
  return 0;
9
}
10
11
function mMouseOver(e)
12
{	
13
  $(this)
14
  // stop any animation that took place before this

15
  .stop()
16
  // step 1. change the image file and change the cursor 

17
  .css({backgroundImage: 'url('+site_url+'img/nav-over.jpg)',cursor: 'pointer'})
18
  // step.2 move up the navigation item a bit

19
  .animate({ backgroundPosition:'(' + _getHPos( this.id ) +'px -30px}'},"fast",
20
    // this section will be executed after the step.2 is done

21
	function(){ 
22
	  $(this)
23
	    .children()
24
		  // step. 3 move the white box down

25
		  .animate({backgroundPosition:'(0px -40px)'},20)
26
		  // step 4. move the white box down

27
		  .animate({backgroundPosition:'(0px -20px)'},"fast");
28
	  $(this)
29
		// step 4. move the navigation item down

30
		.animate({backgroundPosition:'(' + _getHPos( this.id ) +'px 50px)'},"fast")
31
		// step 5. move the navigation item to its final position

32
		.animate({backgroundPosition:'(' + _getHPos( this.id ) +'px 25px)'},"fast");
33
	  // store the parent element id for later usage

34
	  var parent = this;
35
	  $(this)
36
		.children()
37
		  // step 5. move the white box to its final position

38
		  .animate( {backgroundPosition:'(0px -45px)'},"fast",
39
			// this section will be executed after the step.2 is done

40
			function(){
41
			  // step.6 change the image to its original image	

42
			  $(parent).css({backgroundImage: 'url(img/nav.jpg)'});
43
			});	
44
	});
45
}

Мне нужно вам объяснить тут несколько моментов:

  1. Функция _getHPos() используется для подгонки позиции по горизонтали фонового изображения каждого элемента.
    Например: значением начального положения фонового изображения элемента «Home» будет 0, значением начального положения фонового изображения элемента «About» будет -98px, и т.д.
  2. Также обратите внимание, что в начале функции мы вызываем функцию «stop». Мы ее вызываем, чтобы убедиться, что все анимации, выполняемые до возникновения события «mouse over», остановились.
    Зачем? Мы позже добавим другую анимацию, запускаемую при возникновении события «mouse out».
    Теперь давайте представим, что пользователь перемещает курсор поверх элемента и затем быстро перемещает курсор куда-то еще, а затем возвращает его опять поверх того же элемента.
    Если мы не остановим текущую анимацию перед вызовом обработчика для вновь возникшего события, то у нас будет задержка, поскольку часть текущей анимации будет еще находится в очереди или, что еще хуже, анимация станет нелогичной и надоест пользователю.

Шаг 5.2: Обработчик для события mouseout

Теперь с этим завершили. Давайте создадим раскадровку для анимации, выполняемой при возникновении события mouseout.

При перемещении курсора за пределы элемента:

  • Опустить вниз элемент навигационного меню.
  • Опустить белый прямоугольник вниз.
  • Поднять элемент навигационного меню вверх.
  • Переместить элемент навигационного меню в его изначальное положение.
  • Переместить белый прямоугольник в его изначальное положение (элемент скрыт).
  • Вернуть изначальный вид курсора.

Код для реализации этих действий приводится ниже:

1
function mMouseOut(e)
2
{			
3
  $(this)
4
  // stop any animation that took place before this

5
  .stop()
6
  // step.1 move down navigation item

7
  .animate({backgroundPosition:'(' + _getHPos( this.id ) +'px 40px )'}, "fast", 
8
    // this section will be executed after the step.1 is done

9
    function(){
10
      // step.2 white box move really fast

11
      $(this).children().animate({backgroundPosition:'(0px 70px)'}, "fast");
12
      // step 3. move navigation item up

13
      $(this).animate( {backgroundPosition:'(' + _getHPos( this.id ) +'px -40px)'}, "fast", 
14
      // this section will be executed after the step.3 is done

15
        function(){
16
          // step 4. move navigation item ot its original position

17
          $(this).animate( {backgroundPosition:'(' + _getHPos( this.id ) +'px -25px)'}, "fast",
18
            // this section will be executed after the step.4 is done

19
            function(){
20
              // move white box to its original position, ready for next animation

21
              $(this).children().css({ backgroundPosition:'0px -60px'});
22
            })
23
        })
24
    })
25
    .css({backgroundImage: 'url(img/nav.jpg)', cursor: ''});
26
}

Шаг 5.3: Обработчик события сlick

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

1
function mClick(e)
2
{
3
  location.href = this.id;
4
}

Конечно же, вы можете добавить вместо этого любой необходимый вам адрес. За счет этой конкретной функции браузер будет перенаправлен по [current_url]/[navigation_id], так что для элемента «home» адресом будет ‘[current_url]/home’, для «about» – ‘[current_url]/about’ и т.д.

Шаг 5.4: Указатель текущей страницы

Конечно же, нам необходим индикатор того, что мы уже находимся на какой-то странице. Для этого нам необходим еще один класс CSS.
Мы назовем этот класс ‘active’. Например: если мы находимся на странице 'home', то код HTML будет следующим:

1
<div id="home" class="pri-nav active"><div><a href="home">home</a></div></div>

Или если мы находимся на странице 'about', то код HTML будет следующим:

1
<div id="about" class="pri-nav active"><div><a href="about">about</a></div></div>

и т.д.

Итак, теперь идея состоит в том, что после загрузки страницы при помощи нашего скрипта проверяется, какой элемент навигационного меню имеет класс 'active'.
Затем мы применяем к нему анимационный эффект. И нам необходимо убедиться, что при возникновении любых других событий (‘mouseover’, ‘mouseout’, ‘click’) к элементу с классом 'active' не применяется никаких анимационных эффектов.

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

1
var site_url = '';
2
var nav  = [ '#home', '#about', '#services', '#solutions', '#contact' ];
3
4
$(document).ready(function(){
5
  setBkgPos();
6
7
  for ( i = 0; i < nav.length; i++ ) {
8
    $(nav[i]).bind( 'mouseover', mMouseOver );
9
    $(nav[i]).bind( 'mouseout', mMouseOut );
10
    $(nav[i]).bind( 'click', mClick );
11
  }
12
13
  for ( i = 0; i < nav.length; i++ ) {
14
    // element with ‘active’ class will  start animation 

15
    if ( $(nav[i]).get(0).className.indexOf('active') >= 0 ){
16
      $(nav[i])
17
      .animate({ backgroundPosition:'(' + _getHPos( nav[i] ) +'px -30px}'},"fast",
18
        function(){ 
19
          $(this)
20
            .children()
21
            .animate({backgroundPosition:'(0px -40px)'},20)
22
            .animate({backgroundPosition:'(0px -20px)'},"fast");
23
          $(this)
24
            .animate({backgroundPosition:'(' + _getHPos( nav[i] ) +'px 50px)'},"fast")
25
            .animate({backgroundPosition:'(' + _getHPos( nav[i] ) +'px 25px)'},"fast");
26
          var parent = this;
27
          $(this)
28
            .children()
29
            .animate( {backgroundPosition:'(0px -45px)'},"fast",
30
			  function(){
31
                $(parent).animate({backgroundPosition:'(' + _getHPos( parent.id ) +'px 25px)'},"fast");
32
                $(parent).css({backgroundImage: 'url(img/nav.jpg)'});
33
              });
34
        });
35
        break;
36
    }
37
  }
38
});

Завершено!

Вот и готово наше стильное небольшое меню.

Скачать исходный код руководства в формате ZIP

Посмотреть демоверсию!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.