Меню сайту Google Nexus

20

Від автора: Підручник про те, як відтворити выскальзывающее бічне меню-колонку, яке можна побачити на сайті GoogleNexus 7.

Сьогодні я хочу показати вам, як реконструювати бічне меню-колонку сторінки Google Nexus 7. Воно вислизає з гарним ефектом, і ще при цьому розкриваються підпункти. При проведенні мишею над спеціальною іконкою меню відображаються іконки бічної колонки. При клацанні по іконці бічне меню буде відображатися повністю. Перший елемент бічного меню-стовпчики – це поле введення для пошуку, стилі якого такі ж, як у решти пунктів.

Меню сайту Google NexusМеню сайту Google Nexus

Реконструкція цього меню буде проводитися за допомогою невпорядкованих вкладених списків і декількох переходів CSS. Ми скористаємося JavaScript’ом для застосування класів до ефектів відкриття та обробки подій проведення миші і клацання. З допомогою медиазапроса ми підженемо» розмір, щоб підходило для маленьких пристроїв. Отже, давайте почнемо!

Розмітка

Наше меню буде складатися з двох основних частин: головного, того, яке буде знаходитися вгорі, як верхній колонтитул і бічного. Ми додамо клас «gn-menu-main» до першого з них і обернем друге елемент nav. Ви, звичайно, можете використовувати будь-яку бажану вами структуру. Перший елемент меню буде містити посилання-якір і елемент nav:

  • Menu
  • Codrops

Усередині елемента nav ми додамо ще один пакувальник, який допоможе нам приховати для браузерів Windows негарну смугу прокручування. Основа цього підменю – невпорядкований список з класом «gn-menu». Він буде складатися з елементів списку, у кількох з них є субсписок. Першим елементом стане спеціальний input пошуку:

  • Search
  • Downloads

    • Vector Illustrations
    • Photoshop files
  • Settings

Тепер давайте призначимо стилі.

CSS

Зверніть увагу, чпо в CSS не буде вендорних префіксів, але ви знайдете їх у файлах. Почнемо з установки border-box для всіх box-sizing:

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

Так як ми застосуємо шрифти, іконки, то перейдемо до IcoMoon і виберемо красиві іконки з набору EcoIco Метью Скайлза (MatthewSkiles).

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

Так само визначимо декілька стилів стану проведення мишею, де ми міняємо кольору. Першим пунктом бічного меню-стовпчики, де у нас буде поле пошуку, знадобиться спеціальний стиль при проведенні мишею. Тут у нас не буде посилання, що заповнює весь пункт, тому давайте визначимо стан проведення мишею до li і проконтролюємо, що трапиться з іконкою (якорем) і самим li:

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

Перший пункт списку буде спеціальним пусковим елементом і, так як ми будемо приховувати текст і застосуємо до іконки меню псевдоэлемент, то встановимо user-select none на, а ширину таку ж, як висота пунктів.

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

Останній пункт нашого основного списку буде float: right і ми поміняємо border-right:

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

У посилань головного меню буде відступ, а тексту ми призначимо трохи інші стилі:

.gn-menu-main > li > a {
padding: 030px;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: bold;
}

Очистимо плаваючі елементи за допомогою наступного микрохака clearfix Ніколаса Галлахера (NicolasGallagher):

.gn-menu-main:after {
display: table;
clear: both;
content: «;
}

Чудово, тепер не вистачає лише стилю іконки меню, але давайте відкладемо його на потім, коли визначимо інші псевдокласи іконки.

Перейдемо до упаковщику бічного меню-колонки. Навіщо нам ці додаткові пакувальники? Ну, якщо ви не проти видимої смуги прокручування, то можна звільнитися від них і просто встановити меню на overflow-y: scroll. Але так як смуга прокрутки дійсно сильно псує дизайн в браузерах на Windows, то для її приховування ми зробимо маленький фокус. Встановимо основний пакувальник на overflow hidden з певною шириною (спочатку достатньою для того, щоб було видно смугу з іконками). Потім призначимо упаковщику прокрутки трохи більшу ширину і висоту в 100%. Смуга прокрутки буде прихована. Наше меню потім збільшиться до потрібної висоти і буде здатне прокручуватися.

Спочатку нам потрібно приховати меню, тому призначимо йому негативне ліве значення (його ширини).

.gn-menu-wrapper {
position: fixed;
top: 60px;
bottom: 0;
left: 0;
overflow: hidden;
width: 60px; /* буде зроблений перехід до 340px */
border-top: 1px solid #c6d0da;
background: white;
transform: translateX(-60px); /* буде зроблений перехід до 0px */
transition: transform 0.3 s, width 0.3 s;
}
.gn-scroller {
position: absolute;
overflow-y: scroll;
width: 370px;
height: 100%;
}
.gn-menu {
border-bottom: 1pxsolid#c6d0da;
text-align: left;
font-size: 18px;
}

Для поділу пунктів списку давайте додамо тінь блоку. Так нам вдасться уникнути подвійних ліній при скрывании елементів підменю:

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

Додамо перехід до пунктів списку підменю і встановимо їх початкову висоту на 0:

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

Колір буде трохи світліше, ніж у елементів батьківського меню:

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

Тепер призначимо стилі спеціальному елементу пошуку і особливо його input. Нам потрібно, щоб вони були дійсно тонкими, як сторінці 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;
}
/* заповнювач */
.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
}

В більшості браузерів текст-підказка буде ховатися при клацанні по input, чого користувачам буде набагато легше зрозуміти, що це власне input. У Chrome така поведінка відсутня, так що ми скористаємося невеликим прийомом для симуляції того ж самого, встановивши колір тексту-підказки на прозорий при клацанні користувача input та фокусування на ньому:

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

При проведенні мишею ми змінюємо колір тексту input на білий, точно так само, як для інших посилань-якорів (це той текст, який вводить користувач):

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

Те ж саме зробимо з текстом-підказкою:

/* текст-підказка */
.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, ми дозволимо своєму пошуковому input початися прямо з самого лівого краю елемента списку. Але пам’ятайте, у нашого input великий відступ, тому текст буде починатися тільки після іконки пошуку. При клацанні по іконці пошуку насправді ми клацаємо на input, вводячи його в фокус.

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

Тепер давайте призначимо стилі псевдоэлементу іконок::before. Ми встановимо їх на inline-block і призначимо ширину 60 px. Нам доведеться скинути всі стилі шрифтів, так як зараз ми скористаємося своїм шрифтом-іконкою, включеним в початок 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. Тому ми обернем ці окремі випадки в діапазон, який просто приховаємо, встановивши ширину і висоту на 0, а overflow – на hidden. Чому просто не скористатися display: none? Приховавши подібний контент, ми зробимо його недоступним для екранних дикторів, тому давайте переконаємося, що не «стерли» нічого для них важливого:

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

І не забудемо про маленьку іконку в основному меню. Отже, ми не станемо тут застосовувати іконку з шрифту, хоча могли б, звичайно. Замість цього ми створимо її з допомогою тіні блоку і застосуємо контрастні кольори (фоновий і синій) для створення трьох ліній. Також, якщо хочете, можна застосувати тут градієнт.

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

При проведенні мишею ми змінюємо кольору тіні блоку на зворотні:

.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: 03pxwhite, 0-6px#5993cd, 0-9pxwhite, 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 screenand (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();
varself = 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(); } );

Як тільки меню-іконка виявиться у вікні перегляду, проведення над ним мишею змусить вислизнути залишок меню. Якщо після його появи клацнути де-небудь по сторінці, меню знову має забратися з виду. Нам потрібно прив’язати до документа відповідна подія (клацання або дотик).

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

А ось остаточна функция_initEvents і способи відкриття і закриття меню.

_initEvents : function() {
varself = 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();
}

От і все! Дякую вам за прочитання статті і сподіваюся, що вам сподобався цей підручник і виявився корисним!