Анимированное меню с помощью jQuery
ИСХОДНИКИ
У нас будут отображены категории меню ресторана. В каждом блоке с контентом будут перечислены какие-то напитки и блюда. Сразу после появления блока с контентом меню скроется. При клике по кнопке закрытия, контент скроется и отобразится меню.
Итак, начнем!
Структура
В HTML у нас будут несколько элементов для фонового изображения, сетки, перекрывающей его, иконки загрузки и главного меню. Структура будет выглядеть так:
<div id="ac_background" class="ac_background">
<img class="ac_bgimage" src="images/Default.jpg" style="max-width:600px;" alt="Фон"/>
<div class="ac_overlay"></div>
<div class="ac_loading"></div>
</div>
<img class="ac_bgimage" src="images/Default.jpg" style="max-width:600px;" alt="Фон"/>
<div class="ac_overlay"></div>
<div class="ac_loading"></div>
</div>
После загрузки страницы отобразится изображение по умолчанию Default.jpg. При клике по какому-то пункту меню, фоновое изображение будет перекрываться другим, а само оно исчезнет.
Меню заключим в блок div с классом “ac_content”. Здесь будет размещен заголовок и ненумерованный список для пунктов меню, заключенный в div с классом “ac_menu”.
<div id="ac_content" class="ac_content">
<h1><span>Cafe + Bar</span>Dhalia</h1>
<div class="ac_menu">
<ul>
<li>
<a href="images/Appetizers.jpg">Appetizers</a>
<div class="ac_subitem">
<span class="ac_close"></span>
<h2>Appetizers</h2>
<ul>
<li>
A wonderful serenity has taken possession
of my entire soul, like these sweet mornings
of spring which I enjoy with my whole heart.
</li>
<li>Lobster Bisque</li>
<li>Smoked Salmon Terrine</li>
<li>Tuna Ceviche</li>
<li>Wild Mushroom Flan</li>
<li>Almond Bruschetta</li>
<li>Green Chilli Canapee</li>
<li>Artichoke Rucula Salad</li>
</ul>
</div><!-- ac_subitem-->
</li>
...
</ul>
</div><!-- ac_menu -->
</div><!-- ac_content -->
<h1><span>Cafe + Bar</span>Dhalia</h1>
<div class="ac_menu">
<ul>
<li>
<a href="images/Appetizers.jpg">Appetizers</a>
<div class="ac_subitem">
<span class="ac_close"></span>
<h2>Appetizers</h2>
<ul>
<li>
A wonderful serenity has taken possession
of my entire soul, like these sweet mornings
of spring which I enjoy with my whole heart.
</li>
<li>Lobster Bisque</li>
<li>Smoked Salmon Terrine</li>
<li>Tuna Ceviche</li>
<li>Wild Mushroom Flan</li>
<li>Almond Bruschetta</li>
<li>Green Chilli Canapee</li>
<li>Artichoke Rucula Salad</li>
</ul>
</div><!-- ac_subitem-->
</li>
...
</ul>
</div><!-- ac_menu -->
</div><!-- ac_content -->
Для каждого пункта меню создадим блок div с классом “ac_subitem”, в котором будет содержаться контент. Сюда мы поместим другой список (не обязательно список, можно все, что угодно).
Ссылки в главном меню будут вести к изображениям, которые отобразятся при клике на соответствующий пункт меню.
Теперь давайте разберемся со стилями.
CSS
В самом начале давайте подключим файл reset.css:
@import url('reset.css');
Цвет текста под ссылки будет белым:
a{
color:#fff;
text-decoration:none;
}
color:#fff;
text-decoration:none;
}
Фоновые изображения будут назначаться с помощью javascript, поэтому мы не назначим ни одного из них через CSS. Размеры и расположение изображений также будут считаться динамически и будут зависеть от размеров пользовательских мониторов:
img.ac_bgimage{
position:fixed;
left:0px;
top:0px;
opacity:0.8;
display:none;
}
position:fixed;
left:0px;
top:0px;
opacity:0.8;
display:none;
}
Поверх изображения отобразим специальный паттерн, который придаст ему красивый вид:
.ac_overlay{
width:100%;
height:100%;
position:fixed;
top:0px;
left:0px;
background:transparent url(../images/pattern.png) repeat top left;
}
width:100%;
height:100%;
position:fixed;
top:0px;
left:0px;
background:transparent url(../images/pattern.png) repeat top left;
}
Иконку загрузки поместим в правый верхний угол страницы. Она будет отображаться во время смены изображений:
.ac_loading{
position:fixed;
top:10px;
right:10px;
background:#000 url(../images/loader.gif) no-repeat center center;
width:50px;
height:50px;
border-radius:10px 10px 10px 10px;
z-index:999;
opacity:0.7;
display:none;
}
position:fixed;
top:10px;
right:10px;
background:#000 url(../images/loader.gif) no-repeat center center;
width:50px;
height:50px;
border-radius:10px 10px 10px 10px;
z-index:999;
opacity:0.7;
display:none;
}
Блок с контентом расположим в центре страницы. Для этого присвоим атрибуту top значение 50% и уменьшим его высоту, присвоив атрибуту margin-top значение -65px. Так он расположится прямо по центру:
.ac_content{
position:fixed;
height:90px;
width:100%;
top:50%;
left:0px;
margin-top:-65px;
}
position:fixed;
height:90px;
width:100%;
top:50%;
left:0px;
margin-top:-65px;
}
Фон под заголовком слева будет черным полу-прозрачным. Стили для заголовка h1 и span мы определим отдельно. Справа добавим рамку толщиной в 1 пиксель, чтобы визуально отделить заголовок от меню:
.ac_content h1{
background:transparent url(../images/bg_menu.png) repeat top left;
display:block;
float:left;
width:90px;
height:50px;
padding:20px;
font-size:36px;
font-weight:bold;
line-height:20px;
margin-right:1px;
}
.ac_content h1 span{
display:block;
font-weight:normal;
font-size:14px;
}
Фон блока меню будет таким же. Начальная его ширина будет 0 пикселей. Через javascript мы увеличим ее до ширины окна при загрузке страницы:
.ac_menu{
background:transparent url(../images/bg_menu.png) repeat top left;
float:left;
position:relative;
height:90px;
width:0px;
}
background:transparent url(../images/bg_menu.png) repeat top left;
float:left;
position:relative;
height:90px;
width:0px;
}
Для ненумерованного списка с пунктами меню определим такой стиль:
.ac_menu > ul{
float:right;
}
float:right;
}
Высота элементов списка будет подсчитана определенным образом, для них мы также зададим атрибут overflow: hidden, так как нам необходимо, чтобы они выплывали снизу. Если не задать атрибут overflow: hidden, то ссылки будут видны во время анимации:
.ac_menu > ul > li{
float:left;
position:relative;
height:90px;
overflow:hidden;
}
float:left;
position:relative;
height:90px;
overflow:hidden;
}
Изначально ссылки будут скрыты с помощью задания атрибутов margin-top и opacity. После мы плавно переместим их на середину (margin-top: 0px) и сделаем их видимыми, увеличив значение opacity. Причем сделаем это так, чтобы они немножко задерживались, тем самым создадим интересный эффект:
.ac_menu > ul > li a{
margin-top:60px;
opacity:0;
display:block;
height:90px;
padding:0px 10px;
text-align:center;
line-height:90px;
outline:none;
font-size:18px;
font-weight:bold;
text-shadow:1px 1px 1px #000;
}
margin-top:60px;
opacity:0;
display:block;
height:90px;
padding:0px 10px;
text-align:center;
line-height:90px;
outline:none;
font-size:18px;
font-weight:bold;
text-shadow:1px 1px 1px #000;
}
Блоки с контентом будут шириной в 400 пикселей и начальной высотой в 0 пикселей. Мы плавно увеличим это значение потом, а также значение margin-top, чтобы окошко появлялось из середины:
.ac_subitem{
width:400px;
height:0px; /* animate to 400px */
top:50%;
right:0px;
margin-top:0px; /* animate to -200px */
position:fixed;
z-index:99;
overflow:hidden;
background:transparent url(../images/bg_menu.png) repeat top left;
}
width:400px;
height:0px; /* animate to 400px */
top:50%;
right:0px;
margin-top:0px; /* animate to -200px */
position:fixed;
z-index:99;
overflow:hidden;
background:transparent url(../images/bg_menu.png) repeat top left;
}
Определим также некоторые стили для блока с контентом:
.ac_subitem h2{
font-size:22px;
font-weight:bold;
color:#fff;
padding: 40px 0px 0px 40px;
text-shadow:0px 0px 1px #000;
}
.ac_subitem ul{
padding:0px 40px;
}
.ac_subitem ul li{
margin:10px 0px;
}
.ac_subitem ul li:first-child{
font-size:14px;
text-transform:none;
border-bottom:1px dotted #333;
padding-bottom:15px;
margin-bottom:15px;
}
Добавим иконку закрытия данного блока в его правый верхний угол:
span.ac_close{
float:right;
margin:10px;
width:11px;
height:12px;
cursor:pointer;
background:transparent url(../images/close.png) no-repeat top left;
opacity:0.4;
}
span.ac_close:hover{
opacity:1.0;
}
float:right;
margin:10px;
width:11px;
height:12px;
cursor:pointer;
background:transparent url(../images/close.png) no-repeat top left;
opacity:0.4;
}
span.ac_close:hover{
opacity:1.0;
}
Это все насчет стиля. Перейдем к анимации.
JavaScipt
Для анимации мы будем использовать дополнительный плагин. Подключите его сразу после подключения jQuery.
Сперва объявим переменные:
var $ac_background = $('#ac_background'),
$ac_bgimage = $ac_background.find('.ac_bgimage'),
$ac_loading = $ac_background.find('.ac_loading'),
$ac_content = $('#ac_content'),
$title = $ac_content.find('h1'),
$menu = $ac_content.find('.ac_menu'),
$mainNav = $menu.find('ul:first'),
$menuItems = $mainNav.children('li'),
totalItems = $menuItems.length,
$ItemImages = new Array();
$ac_bgimage = $ac_background.find('.ac_bgimage'),
$ac_loading = $ac_background.find('.ac_loading'),
$ac_content = $('#ac_content'),
$title = $ac_content.find('h1'),
$menu = $ac_content.find('.ac_menu'),
$mainNav = $menu.find('ul:first'),
$menuItems = $mainNav.children('li'),
totalItems = $menuItems.length,
$ItemImages = new Array();
Загрузим все изображения, так что добавим все ссылки, а также дополнительно объявим текущее изображение:
$menuItems.each(function(i) {
$ItemImages.push($(this).children('a:first').attr('href'));
});
$ItemImages.push($ac_bgimage.attr('src'));
А теперь приступим к нашей главной функции:
var Menu = (function(){
var init = function() {
loadPage();
initWindowEvent();
},
loadPage = function() {
/*
1- загружает все фоновые и другие изображения;
2- отображает фоновое изображение;
3- скрывает и открывает меню;
4- отображает пункты меню;
5- инициализирует события, связанные с пунктами меню
*/
$ac_loading.show(); //отображение иконки загрузки
$.when(loadImages()).done(function(){
$.when(showBGImage()).done(function(){
//скрывает иконку загрузки
$ac_loading.hide();
$.when(slideOutMenu()).done(function(){
$.when(toggleMenuItems('up')).done(function(){
initEventsSubMenu();
});
});
});
});
},
showBGImage = function() {
return $.Deferred(
function(dfd) {
//подсчитывает размеры изображения
adjustImageSize($ac_bgimage);
$ac_bgimage.fadeIn(1000, dfd.resolve);
}
).promise();
},
slideOutMenu = function() {
/* подсчитывает новую ширину меню */
var new_w = $(window).width() - $title.outerWidth(true);
return $.Deferred(
function(dfd) {
//скрывает меню
$menu.stop()
.animate({
width : new_w + 'px'
}, 700, dfd.resolve);
}
).promise();
},
/* скрывает / отображает пункт меню */
toggleMenuItems = function(dir) {
return $.Deferred(
function(dfd) {
/*
скрывает / отображает пункты меню.
каждый раз разная анимация.
*/
$menuItems.each(function(i) {
var $el_title = $(this).children('a:first'),
marginTop, opacity, easing;
if(dir === 'up'){
marginTop = '0px';
opacity = 1;
easing = 'easeOutBack';
}
else if(dir === 'down'){
marginTop = '60px';
opacity = 0;
easing = 'easeInBack';
}
$el_title.stop()
.animate({
marginTop : marginTop,
opacity : opacity
}, 200 + i * 200 , easing, function(){
if(i === totalItems - 1)
dfd.resolve();
});
});
}
).promise();
},
initEventsSubMenu = function() {
$menuItems.each(function(i) {
var $item = $(this), // <li>
$el_title = $item.children('a:first'),
el_image = $el_title.attr('href'),
$sub_menu = $item.find('.ac_subitem'),
$ac_close = $sub_menu.find('.ac_close');
/* пользователь кликает по пункту меню */
$el_title.bind('click.Menu', function(e) {
$.when(toggleMenuItems('down')).done(function(){
openSubMenu($item, $sub_menu, el_image);
});
return false;
});
/* контент скрывается */
$ac_close.bind('click.Menu', function(e) {
closeSubMenu($sub_menu);
return false;
});
});
},
openSubMenu = function($item, $sub_menu, el_image) {
$sub_menu.stop()
.animate({
height : '400px',
marginTop : '-200px'
}, 400, function() {
//the bg image changes
showItemImage(el_image);
});
},
/* меняется фоновое изображение */
showItemImage = function(source) {
//если это текущее изображение, то вернет 0
if($ac_bgimage.attr('src') === source)
return false;
var $itemImage = $('<img class="ac_bgimage" src="'+source+'" style="max-width:600px;" alt="Background">');
$itemImage.insertBefore($ac_bgimage);
adjustImageSize($itemImage);
$ac_bgimage.fadeOut(1500, function() {
$(this).remove();
$ac_bgimage = $itemImage;
});
$itemImage.fadeIn(1500);
},
closeSubMenu = function($sub_menu) {
$sub_menu.stop()
.animate({
height : '0px',
marginTop : '0px'
}, 400, function() {
//отображение элементов
toggleMenuItems('up');
});
},
/*
on window resize, ajust the bg image dimentions,
and recalculate the menus width
*/
initWindowEvent = function() {
/* назначает ширину фонового изображения */
$(window).bind('resize.Menu' , function(e) {
adjustImageSize($ac_bgimage);
/* считает новую ширину меню */
var new_w = $(window).width() - $title.outerWidth(true);
$menu.css('width', new_w + 'px');
});
},
/* расширяет изображение и располагает его по центру */
adjustImageSize = function($img) {
var w_w = $(window).width(),
w_h = $(window).height(),
r_w = w_h / w_w,
i_w = $img.width(),
i_h = $img.height(),
r_i = i_h / i_w,
new_w,new_h,
new_left,new_top;
if(r_w > r_i){
new_h = w_h;
new_w = w_h / r_i;
}
else{
new_h = w_w * r_i;
new_w = w_w;
}
$img.css({
width : new_w + 'px',
height : new_h + 'px',
left : (w_w - new_w) / 2 + 'px',
top : (w_h - new_h) / 2 + 'px'
});
},
/* загружает все изображения */
loadImages = function() {
return $.Deferred(
function(dfd) {
var total_images = $ItemImages.length,
loaded = 0;
for(var i = 0; i < total_images; ++i){
$('<img style="max-width:600px;" alt="">').load(function() {
++loaded;
if(loaded === total_images)
dfd.resolve();
}).attr('src' , $ItemImages[i]);
}
}
).promise();
};
return {
init : init
};
})();
/*
вызов метода init
*/
Menu.init();
</li>
На этом все. Надеюсь, вам понравился урок!