Экспериментальная полноэкранная навигация, анимированная с использованием CSS и jQuery, которая расширяется в пределах круга.
Я просматривал приложение Ping iOS. Эффект при нажатии на круг для переключения страницы слишком крут, поэтому я хочу вам показать что-то подобное в CSS и jQuery. Результат довольно интересный, поэтому мы решили выпустить этот фрагмент :) Это экспериментальная навигация, но она поддерживается всеми основными браузерами - мы использовали Velocity.js - и я уверен, что вы, ребята, найдете способ использовать это!
Создание структуры
В структуре HTML мы использовали неупорядоченный список для навигации, семантически завернутый в элемент <nav>
. Содержимое .cd-overlay-nav
и .cd-overlay-content
используются для анимации круглой формы. Именно они используются в качестве контейнеров, чтобы расположить круги прямо за иконкой верхнего правого меню, а элементы <span>
внутри - это два цветных круга, которые расширяются. Наконец, .cd-nav-trigger
- это значок меню, который анимируется в виде перекрестного значка.
<header>
<a class="cd-logo" href="#0"><img src="img/cd-logo.svg" alt="Logo"></a>
</header>
<nav>
<ul class="cd-primary-nav">
<li><a href="#0">The team</a></li>
<li><a href="#0">Our services</a></li>
<li><a href="#0">Our projects</a></li>
<li><a href="#0">Start a project</a></li>
<li><a href="#0">Join In</a></li>
<li><a href="#0">Create an account</a></li>
</ul>
</nav>
<main class="cd-content">
<!-- your content here -->
</main>
<div class="cd-overlay-nav">
<span></span>
</div> <!-- cd-overlay-nav -->
<div class="cd-overlay-content">
<span></span>
</div> <!-- cd-overlay-content -->
<a href="#0" class="cd-nav-trigger">Menu<span class="cd-icon"></span></a>
Добавление стиля
Если вы посмотрите на CSS, вы заметите, что кнопка триггера .cd-nav-trigger
находится в position:fixed
в правом верхнем углу. Чтобы эффект работал правильно, нам пришлось центрировать контейнеры (.cd-overlay-nav
и .cd-overlay-content
) из 2 анимированных кругов прямо за курок. Чтобы сделать это, нам нужно было определить фиксированную высоту и ширину для них обоих. Но если вы посмотрите на элементы <span>
, которые на самом деле являются анимированными кругами, вы можете заметить, что мы не определяли какое-либо значение позиционирования или размера. Поскольку круг должен покрывать весь экран, независимо от размера видового экрана, мы определяем позиционирование (верхнее и левое значения) и размер (ширину) в jQuery.
.cd-nav-trigger {
top: 18px;
right: 5%;
height: 44px;
width: 44px;
z-index: 5;
/* image replacement */
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.cd-overlay-nav, .cd-overlay-content {
/* containers of the 2 main rounded backgrounds - these containers are used to position the rounded bgs behind the menu icon */
position: fixed;
top: 18px;
right: 5%;
height: 4px;
width: 4px;
transform: translateX(-20px) translateY(20px);
}
.cd-overlay-nav span, .cd-overlay-content span {
display: inline-block;
position: absolute;
border-radius: 50%;
will-change: transform;
transform: scale(0);
}
Идея состояла в том, чтобы анимировать значок меню, а не просто заменить «гамбургер» значком «закрыть», поэтому мы добавили элемент <span>
(.cd-icon
) внутри триггера. Таким образом, мы можем создавать и анимировать значок с использованием ::before
и ::after
псевдоэлементов.
.cd-nav-trigger .cd-icon {
/* icon created in CSS */
position: absolute;
left: 50%;
top: 50%;
bottom: auto;
right: auto;
transform: translateX(-50%) translateY(-50%);
display: inline-block;
width: 18px;
height: 3px;
background-color: #ffffff;
z-index: 10;
}
.cd-nav-trigger .cd-icon::before, .cd-nav-trigger .cd-icon:after {
/* upper and lower lines of the menu icon */
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
background-color: inherit;
transition: transform .3s;
}
.cd-nav-trigger .cd-icon::before {
transform: translateY(-6px) rotate(0deg);
}
.cd-nav-trigger .cd-icon::after {
transform: translateY(6px) rotate(0deg);
}
.cd-nav-trigger.close-nav .cd-icon {
/* user clicks on the .cd-nav-trigger element - transform the icon */
background-color: rgba(255, 255, 255, 0);
}
.cd-nav-trigger.close-nav .cd-icon::before, .cd-nav-trigger.close-nav .cd-icon::after {
background-color: white;
}
.cd-nav-trigger.close-nav .cd-icon::before {
transform: translateY(0) rotate(45deg);
}
.cd-nav-trigger.close-nav .cd-icon::after {
transform: translateY(0) rotate(-45deg);
}
Цвет фона меню / триггера изменяется, и он оживлен с небольшой задержкой. Еще раз мы использовали 2 псевдоэлемента для достижения этого эффекта:
.cd-nav-trigger::before, .cd-nav-trigger::after {
/* 2 rounded colored backgrounds for the menu icon */
position: absolute;
top: 0;
left: 0;
border-radius: 50%;
height: 100%;
width: 100%;
transition-property: transform;
}
.cd-nav-trigger::before {
background-color: #091d23;
transform: scale(1);
transition-duration: 0.3s;
transition-delay: 0.4s;
}
.cd-nav-trigger::after {
background-color: #ffb441;
transform: scale(0);
transition-duration: 0s;
transition-delay: 0s;
}
.cd-nav-trigger.close-nav::before {
/* user clicks on the .cd-nav-trigger element - 1st rounded background disappears */
transform: scale(0);
}
.cd-nav-trigger.close-nav::after {
/* user clicks on the .cd-nav-trigger element - 2nd rounded background appears */
transform: scale(1);
transition-duration: 0.3s;
transition-delay: 0.4s;
}
Обработка событий
Прежде чем погрузиться в jQuery, я хотел бы объяснить, что происходит в нескольких простых словах: когда пользователь щелкает / нажимает на кнопку меню, мы анимируем <span>
внутри .cd-overlay-nav
. Когда круг заполняет экран, мы показываем навигацию. Когда пользователь снова нажимает / повторяет триггер, чтобы закрыть навигацию, мы анимируем <span>
внутри содержимого cd-overlay-content
. В конце этой анимации мы скроем первый круг и навигацию, которые все еще там, просто не видны, потому что они имеют более низкий индекс z. Наконец, мы уменьшаем непрозрачность формы второго раунда (желтый в демо), тем самым раскрывая контент - и притворяясь, что контент находится поверх навигации.
О jQuery мы определили положение и размер элемента <span> круги (используя функцию initLayer()
). Мы назначили высоту, равную удвоенной диагонали окна просмотра, а верхнюю (и левую) равную отрицательному значению диагональ окна просмотра (<span>
находится внутри содержимого .cd-overlay-nav
/ cd-overlay-content
и имеет position: absolute
).
Когда пользователь сначала нажимает на .cd-nav-trigger
, мы анимируем элемент span .cd-overlay-nav span
, меняя его значение scale
от 0 до 1 (мы использовали Velocity.js для анимации):
var overlayNav = $('.cd-overlay-nav'),
toggleNav = $('.cd-nav-trigger'),
navigation = $('.cd-primary-nav');
toggleNav.on('click', function(){
if(!toggleNav.hasClass('close-nav')) {
//animate menu icon into a cross icon
toggleNav.addClass('close-nav');
//animate the navigation layer
overlayNav.children('span').velocity({
translateZ: 0,
scaleX: 1,
scaleY: 1,
}, 500, 'easeInCubic', function(){
//show navigation
navigation.addClass('fade-in');
});
}
}
Когда пользователь нажимает кнопку .cd-nav-trigger
, чтобы закрыть меню, мы анимируем значение шкалы диапазона cd-overlay-content span
:
var overlayNav = $('.cd-overlay-nav'),
overlayContent = $('.cd-overlay-content'),
toggleNav = $('.cd-nav-trigger'),
navigation = $('.cd-primary-nav');
toggleNav.on('click', function(){
if(!toggleNav.hasClass('close-nav')) {
//it means navigation is not visible yet - open it and animate navigation layer
//....
} else {
//animate cross icon into a menu icon
toggleNav.removeClass('close-nav');
//animate the content layer
overlayContent.children('span').velocity({
translateZ: 0,
scaleX: 1,
scaleY: 1,
}, 500, 'easeInCubic', function(){
//hide navigation
navigation.removeClass('fade-in');
//scale to zero the navigation layer
overlayNav.children('span').velocity({
translateZ: 0,
scaleX: 0,
scaleY: 0,
}, 0);
//reduce to opacity of the content layer with the is-hidden class
overlayContent.addClass('is-hidden').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){
//wait for the end of the transition and scale to zero the content layer
overlayContent.children('span').velocity({
translateZ: 0,
scaleX: 0,
scaleY: 0,
}, 0, function(){overlayContent.removeClass('is-hidden')});
});
});
}
});