Анимированное меню с помощью jQuery

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

ИСХОДНИКИ

Прикреплённые файлы:
Файл: demo2.zip
Размер: [842,29 Kb] (забрали: 29 раз)

У нас будут отображены категории меню ресторана. В каждом блоке с контентом будут перечислены какие-то напитки и блюда. Сразу после появления блока с контентом меню скроется. При клике по кнопке закрытия, контент скроется и отобразится меню.

Итак, начнем!

Структура

В 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>

После загрузки страницы отобразится изображение по умолчанию 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 —>

Для каждого пункта меню создадим блок div с классом “ac_subitem”, в котором будет содержаться контент. Сюда мы поместим другой список (не обязательно список, можно все, что угодно).

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

Теперь давайте разберемся со стилями.

CSS

В самом начале давайте подключим файл reset.css:

@import url(‘reset.css’);

Цвет текста под ссылки будет белым:

a{
    color:#fff;
    text-decoration:none;
}

Фоновые изображения будут назначаться с помощью javascript, поэтому мы не назначим ни одного из них через CSS. Размеры и расположение изображений также будут считаться динамически и будут зависеть от размеров пользовательских мониторов:

img.ac_bgimage{
    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;
}

Иконку загрузки поместим в правый верхний угол страницы. Она будет отображаться во время смены изображений:

.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;
}


Блок с контентом расположим в центре страницы. Для этого присвоим атрибуту top значение 50% и уменьшим его высоту, присвоив атрибуту margin-top значение -65px. Так он расположится прямо по центру:

.ac_content{
    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;
}

Для ненумерованного списка с пунктами меню определим такой стиль:

.ac_menu > ul{
    float:right;
}

Высота элементов списка будет подсчитана определенным образом, для них мы также зададим атрибут overflow: hidden, так как нам необходимо, чтобы они выплывали снизу. Если не задать атрибут overflow: hidden, то ссылки будут видны во время анимации:

.ac_menu > ul > li{
    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;
}

Блоки с контентом будут шириной в 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;
}

Определим также некоторые стили для блока с контентом:


.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;
}

Это все насчет стиля. Перейдем к анимации.

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();

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


$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>

На этом все. Надеюсь, вам понравился урок!

Добавить комментарий

Ваш адрес email не будет опубликован.