Меню Сайта Google Nexus

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

HTML-код формы:

Мы создаем это меню, используя неупорядоченные, вложенные списки и некоторые CSS переходы. Мы будем пользоваться JavaScript, чтобы применить классы для начальных эффектов, наведении и для щелчка.

Так давайте начнем!

РАЗМЕТКИ

Наше меню будет состоять из двух главных частей: главное меню, то, что вы можете посмотреть вверху подобно заголовку, и боковое меню. Мы первому меню дадим класс "gn-menu-main", а второе меню обернем тегом NAV. Конечно, вы можете использовать любую структуру, которое вы предпочитаете. Первый пункт меню будет содержать якорь иконкы меню и NAV элемент:

<ul id="gn-menu" class="gn-menu-main">
    <li class="gn-trigger">
        <a class="gn-icon gn-icon-menu"><span>Menu</span></a>
        <nav class="gn-menu-wrapper">
            <!-- ... -->
        </nav>
    </li>
    <li><a href="http://tympanus.net/codrops">Codrops</a></li>
    <li><!-- ... --></li>
    <!-- ... -->
</ul>

Внутри NAV элемента мы добавим другое меню. Сердцем этого подменю является неупорядоченный список с классом "GN-menu". Он будет состоять из элементов списка, некоторые из которых будут иметь доступа к списку. Первый пункт будет специальный вход для поиска:

<div class="gn-scroller">
    <ul class="gn-menu">
        <li class="gn-search-item">
            <input placeholder="Search" type="search" class="gn-search">
            <a class="gn-icon gn-icon-search"><span>Search</span></a>
        </li>
        <li>
            <a class="gn-icon gn-icon-download">Downloads</a>
            <ul class="gn-submenu">
                <li><a class="gn-icon gn-icon-illustrator">Vector Illustrations</a></li>
                <li><a class="gn-icon gn-icon-photoshop">Photoshop files</a></li>
            </ul>
        </li>
        <li><a class="gn-icon gn-icon-cog">Settings</a></li>
        <li><!-- ... --></li>
        <!-- ... -->
    </ul>
</div><!-- /gn-scroller -->

CSS

Давайте начнем, установив границы border-box для box-sizing:

*,
*:after,
*::before {
    box-sizing: border-box;
}

Так как мы будем использовать значок шрифта для иконок, зайдем в IcoMoon и выберем некоторые хорошие иконы.

@font-face {
    font-weight: normal;
    font-style: normal;
    font-family: 'ecoicons';
    src: url("../fonts/ecoicons/ecoicons.eot");
    src: url("../fonts/ecoicons/ecoicons.eot?#iefix") format("embedded-opentype"), url("../fonts/ecoicons/ecoicons.woff") format("woff"), url("../fonts/ecoicons/ecoicons.ttf") format("truetype"), url("../fonts/ecoicons/ecoicons.svg#ecoicons") format("svg");
}

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

Но перед этим давайте пропишем несколько стилей:

.gn-menu-main,
.gn-menu-main ul {
    margin: 0;
    padding: 0;
    background: white;
    color: #5f6f81;
    list-style: none;
    text-transform: none;
    font-weight: 300;
    font-family: 'Lato', Arial, sans-serif;
    line-height: 60px;
}

Вот некоторые общие стили для списков и подсписков.

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

.gn-menu-main {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 60px;
    font-size: 13px;
}

Общий стиль для всех ссылок в нашем меню и подменю будет следующим:

.gn-menu-main a {
    display: block;
    height: 100%;
    color: #5f6f81;
    text-decoration: none;
    cursor: pointer;
}

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

.no-touch .gn-menu-main a:hover,
.no-touch .gn-menu li.gn-search-item:hover,
.no-touch .gn-menu li.gn-search-item:hover a {
    background: #5f6f81;
    color: white;
}

Дочерний элемент списка будет иметь float: left и border: right:

.gn-menu-main > li {
    display: block;
    float: left;
    height: 100%;
    border-right: 1px solid #c6d0da;
    text-align: center;
}

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

.gn-menu-main li.gn-trigger {
    position: relative;
    width: 60px;
    user-select: none;
}

Последний пункт нашего главного списка перенесем в право, и дадим ему левую границу:

.gn-menu-main > li:last-child {
    float: right;
    border-right: none;
    border-left: 1px solid #c6d0da;
}

Якорь для главного меню будут иметь некоторое дополнение и мы стилизуем текст немного по-другому:

.gn-menu-main > li > a {
    padding: 0 30px;
    text-transform: uppercase;
    letter-spacing: 1px;
    font-weight: bold;
}
.gn-menu-main:after {
    display: table;
    clear: both;
    content: '';
}

Давайте перейдем к обертке для бокового меню. Почему нам нужны те добавочные оберткии? Если вы не хотите чтобы была видна полоса прокрутки, вы можете просто выбрав в меню overflow-y: scroll. Но так как полоса прокрутки в нашем случии не красиво смотрица с нашим дизайном, мы будем использовать маленькую хитрость, чтобы скрыть его. Мы установим не verflow-y: scroll а просто verflow-y: hidden, с определенной шириной. Затем мы дадим обертке прокрутки большую ширину и высоту 100%. Полоса прокрутки будет скрыта. Наше меню затем простерется к высоте, которая требуется, и это будет прокручиваемым. Изначально мы хотим скрыть меню, поэтому мы дадим ему отрицательное значение.

.gn-menu-wrapper {
    position: fixed;
    top: 60px;
    bottom: 0;
    left: 0;
    overflow: hidden;
    width: 60px; /* will be transitioned to 340px */
    border-top: 1px solid #c6d0da;
    background: white;
    transform: translateX(-60px); /* will be transitioned to 0px */
    transition: transform 0.3s, width 0.3s;
}
 
.gn-scroller {
    position: absolute;
    overflow-y: scroll;
    width: 370px;
    height: 100%;
}
 
.gn-menu {
    border-bottom: 1px solid #c6d0da;
    text-align: left;
    font-size: 18px;
}

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

.gn-menu li:not(:first-child),
.gn-menu li li {
    box-shadow: inset 0 1px #c6d0da
}

Давайте добавим переход списка нижнего уровня подменю и установим их начальную высоту 0:

.gn-submenu li {
    overflow: hidden;
    height: 0;
    transition: height 0.3s;
}

Цвет дадим немного светлее, чем родительский элемент меню:

.gn-submenu li a {
    color: #c1c9d1
}

Сейчас давайте дадим стиль поиску. Мы хотим сделать это подобно странице Google Nexus, поэтому мы сделаем его фон прозрачным.

input.gn-search {
    position: relative;
    z-index: 10;
    padding-left: 60px;
    outline: none;
    border: none;
    background: transparent;
    color: #5f6f81;
    font-weight: 300;
    font-family: 'Lato', Arial, sans-serif;
    cursor: pointer;
}
 
/* placeholder */
 
.gn-search::-webkit-input-placeholder {
    color: #5f6f81
}
 
.gn-search:-moz-placeholder {
    color: #5f6f81
}
 
.gn-search::-moz-placeholder {
    color: #5f6f81
}
 
.gn-search:-ms-input-placeholder {
    color: #5f6f81
}

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

.gn-search:focus::-webkit-input-placeholder,
.no-touch .gn-menu li.gn-search-item:hover .gn-search:focus::-webkit-input-placeholder {
    color: transparent
}
 
input.gn-search:focus {
    cursor: text
}

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

.no-touch .gn-menu li.gn-search-item:hover input.gn-search {
    color: white
}

Мы также будем делать это для текста заменителя:

/* placeholder */
 
.no-touch .gn-menu li.gn-search-item:hover .gn-search::-webkit-input-placeholder {
    color: white
}
 
.no-touch .gn-menu li.gn-search-item:hover .gn-search:-moz-placeholder {
    color: white
}
 
.no-touch .gn-menu li.gn-search-item:hover .gn-search::-moz-placeholder {
    color: white
}
 
.no-touch .gn-menu li.gn-search-item:hover .gn-search:-ms-input-placeholder {
    color: white
}

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

.gn-menu-main a.gn-icon-search {
    position: absolute;
    top: 0;
    left: 0;
    height: 60px;
}

Теперь дававйте стилизовать ::before псевдо элемент для иконок. Мы установим ему inline-block и дадим ширину 60 пикселей. Мы должны сбросить все стили шрифтов, потому что теперь мы будем использовать наш шрифт, который мы включили в начале CSS-кода:

.gn-icon::before {
    display: inline-block;
    width: 60px;
    text-align: center;
    text-transform: none;
    font-weight: normal;
    font-style: normal;
    font-variant: normal;
    font-family: 'ecoicons';
    line-height: 1;
    speak: none;
    -webkit-font-smoothing: antialiased;
}

Давайте определим контент для всех значков:

.gn-icon-help::before {
    content: "\e000"
}
 
.gn-icon-cog::before {
    content: "\e006"
}
 
.gn-icon-search::before {
    content: "\e005"
}
 
.gn-icon-download::before {
    content: "\e007"
}
 
.gn-icon-photoshop::before {
    content: "\e001"
}
 
.gn-icon-illustrator::before {
    content: "\e002"
}
 
.gn-icon-archive::before {
    content: "\e00d"
}
 
.gn-icon-article::before {
    content: "\e003"
}
 
.gn-icon-pictures::before {
    content: "\e008"
}
 
.gn-icon-videos::before {
    content: "\e009"
}

Как правило, мы хотим, чтобы текст якоря показалось рядом со значком, но иногда, нам нужно показать только значок. Но мы хотим показать не просто пустой якорь, но и текст в HTML-коде. Поэтому мы оборачиваем их в тег span, которую мы потом будем просто скрыть "ширину" и "высоту" 0, а свойство overflow установим hidden. Почему бы не просто использовать display: none? Сокрытие содержимого подобно этому сделало бы это недоступным для чтения с экрана , так мы можем знать, что мы не "стираем" ничего важного для них:

.gn-icon span {
    width: 0;
    height: 0;
    display: block;
    overflow: hidden;
}

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

.gn-icon-menu::before {
    margin-left: -15px;
    vertical-align: -2px;
    width: 30px;
    height: 3px;
    background: #5f6f81;
    box-shadow: 0 3px white, 0 -6px #5f6f81, 0 -9px white, 0 -12px #5f6f81;
    content: '';
}

А при наведении мы будем инвертировать цвета с помощью box-shadow:

.no-touch .gn-icon-menu:hover::before,
.no-touch .gn-icon-menu.gn-selected:hover::before {
    background: white;
    box-shadow: 0 3px #5f6f81, 0 -6px white, 0 -9px #5f6f81, 0 -12px white;
}

И когда оно будет открыто (боковое меню), мы сделаем его более синим.

.gn-icon-menu.gn-selected::before {
    background: #5993cd;
    box-shadow: 0 3px white, 0 -6px #5993cd, 0 -9px white, 0 -12px #5993cd;
}

Последнее, что нам нужно сделать, это определить наши два класса - для открытия меню, для отображения только значков и для показа всего меню. Когда мы наведем указатель мыши на значок меню, будут видны только значки. Давайте назовем этот класс gn-open-part. А другой класс назовем gn-open-all, который применяем либо при клике по иконке основного меню, либо при наведении по области с иконками.

В обоих случаях нам нужно установить translate на 0:

.gn-menu-wrapper.gn-open-all,
.gn-menu-wrapper.gn-open-part {
    transform: translateX(0px);
}

Если мы хотим, чтобы открыть меню в целом, то нам надо установить правильную ширина:

.gn-menu-wrapper.gn-open-all {
    width: 340px;
}

После открытия меню целиком, откроются также пункты подменю:

.gn-menu-wrapper.gn-open-all .gn-submenu li {
    height: 60px;
}

И последнее, но не менее важное, это media query, который позволит меню использовать всю ширину экрана:

[/CODE]

После открытия меню целиком, откроются также пункты подменю:

@media screen and (max-width: 422px) { 
    .gn-menu-wrapper.gn-open-all {
        transform: translateX(0px);
        width: 100%;
    }
 
    .gn-menu-wrapper.gn-open-all .gn-scroller {
        width: 130%;
    }
}

Мы будем также регулировать ширину полосы прокрутки, чтобы она была больше 100%. Наверное, это не столь важно, так как мы не будем видеть полосу прокрутки на большинстве устройств данного размера.

Хорошо, теперь, когда мы уже оформили все, мы еще будем использовать JavaScript-код для логического процесса открытия и закрытия меню (т.е. с использованием классов).

JAVASCRIPT

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

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

_init : function() {
    this.trigger = this.el.querySelector( 'a.gn-icon-menu' );
    this.menu = this.el.querySelector( 'nav.gn-menu-wrapper' );
    this.isMenuOpen = false;
    this.eventtype = mobilecheck() ? 'touchstart' : 'click';
    this._initEvents();
 
    var self = this;
    this.bodyClickFn = function() {
        self._closeMenu();
        this.removeEventListener( self.eventtype, self.bodyClickFn );
    };
}

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

this.trigger.addEventListener( 'mouseover', function(ev) { self._openIconMenu(); } );
this.trigger.addEventListener( 'mouseout', function(ev) { self._closeIconMenu(); } );

Как только меню иконки будет находится в области просмотра, оно приведет к открытию полной версии меню. После того, как она откроется, если мы щелкнем где-нибудь на другом месте, меню снова должно закрыться. Нам нужно связывать соответствующее событие (click или TouchStart) к документу.

this.menu.addEventListener( 'mouseover', function(ev) {
    self._openMenu(); 
    document.addEventListener( self.eventtype, self.bodyClickFn ); 
} );

Наконец, если мы нажмем на значок меню, мы хотим, чтобы меню окрылась, если оно находится в окне просмотра. Нам также нужно связать соответствующее событие (click или touchstart) к документу.

this.trigger.addEventListener( this.eventtype, function( ev ) {
    ev.stopPropagation();
    ev.preventDefault();
    if( self.isMenuOpen ) {
        self._closeMenu();
        document.removeEventListener( self.eventtype, self.bodyClickFn );
    }
    else {
        self._openMenu();
        document.addEventListener( self.eventtype, self.bodyClickFn );
    }
} );

И последнее: мы не хотим, чтобы меню закрылась обратно, если мы щелкаем где-то внутри этого меню. Поскольку мы привязываем событие click/touchstart к документа (когда меню закрывается), мы должны сделать следующее:

this.menu.addEventListener( this.eventtype, function(ev) { ev.stopPropagation(); } );

И вот последняя _initEvents функции и методы, для открытия и закрытия меню.

_initEvents : function() {
    var self = this;
 
    if( !mobilecheck() ) {
        this.trigger.addEventListener( 'mouseover', function(ev) { self._openIconMenu(); } );
        this.trigger.addEventListener( 'mouseout', function(ev) { self._closeIconMenu(); } );
     
        this.menu.addEventListener( 'mouseover', function(ev) {
            self._openMenu(); 
            document.addEventListener( self.eventtype, self.bodyClickFn ); 
        } );
    }
    this.trigger.addEventListener( this.eventtype, function( ev ) {
        ev.stopPropagation();
        ev.preventDefault();
        if( self.isMenuOpen ) {
            self._closeMenu();
            document.removeEventListener( self.eventtype, self.bodyClickFn );
        }
        else {
            self._openMenu();
            document.addEventListener( self.eventtype, self.bodyClickFn );
        }
    } );
    this.menu.addEventListener( this.eventtype, function(ev) { ev.stopPropagation(); } );
},
_openIconMenu : function() {
    classie.add( this.menu, 'gn-open-part' );
},
_closeIconMenu : function() {
    classie.remove( this.menu, 'gn-open-part' );
},
_openMenu : function() {
    if( this.isMenuOpen ) return;
    classie.add( this.trigger, 'gn-selected' );
    this.isMenuOpen = true;
    classie.add( this.menu, 'gn-open-all' );
    this._closeIconMenu();
},
_closeMenu : function() {
    if( !this.isMenuOpen ) return;
    classie.remove( this.trigger, 'gn-selected' );
    this.isMenuOpen = false;
    classie.remove( this.menu, 'gn-open-all' );
    this._closeIconMenu();
}

Ну вот и все! Спасибо за внимание, и надеюсь что вам понравился данный урок.

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



[CODE] [/CODE]


Комментариев нет!