Навигация как на Stripe.Com

demosourse

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

Несколько недель назад на stripe.com был вылит новый дизайн. Он великолепен. Одним из особых мест — стала навигация: вместо привычного выпадающего списка мы видим блоки с отличным оформлением.

Структура

HTML структура состоит из двух основных элементов: nav.main-nav для топ-навигации и div.morph-dropdown-wrapper — контейнера для выпадающих элементов.

Для каждого элемента nav.main-nav создаём li.dropdown.

<header class="cd-morph-dropdown">
	<a href="#0" class="nav-trigger">Open Nav<span aria-hidden="true"></span></a>

	<nav class="main-nav">
		<ul>
			<li class="has-dropdown gallery" data-content="about">
				<a href="#0">About</a>
			</li>

			<li class="has-dropdown links" data-content="pricing">
				<a href="#0">Pricing</a>
			</li>

			<li class="has-dropdown button" data-content="contact">
				<a href="#0">Contact</a>
			</li>
		</ul>
	</nav>

	<div class="morph-dropdown-wrapper">
		<div class="dropdown-list">
			<ul>
				<li id="about" class="dropdown gallery">
					<!-- dropdown content here -->
				</li>

				<li id="pricing" class="dropdown links">
					<!-- dropdown content here -->
				</li>

				<li id="contact" class="dropdown button">
					<!-- dropdown content here -->
				</li>
			</ul>

			<div class="bg-layer" aria-hidden="true"></div>
		</div> <!-- dropdown-list -->
	</div> <!-- morph-dropdown-wrapper -->
</header>

Дополнительный элемент div.bg-layer будет задействован для графических преобразований.

Стили

На небольших устройствах элемент div.morph-dropdown-wrapper будет скрыт; отобразится только при клике по элементу с классом .nav-open.

.cd-morph-dropdown {
  position: relative;
}
.cd-morph-dropdown .morph-dropdown-wrapper {
  display: none;
  position: absolute;
  top: 60px;
  left: 0;
  width: 100%;
}
.cd-morph-dropdown.nav-open .morph-dropdown-wrapper {
  display: block;
}

На устройствах с крупным дисплеем изначально скрыты элементы .dropdown-list и li.dropdown.

@media only screen and (min-width: 1000px) {
	.cd-morph-dropdown .dropdown-list {
	    position: absolute;
	    top: 0;
	    left: 0;
	    visibility: hidden;
  	}
  	.cd-morph-dropdown .dropdown {
	    position: absolute;
	    left: 0;
	    top: 0;
	    opacity: 0;
	    visibility: hidden;
	    width: 100%;
	    transition: opacity .3s, visibility .3s;
  	}
}

При наведении курсором мыши по элементам внутри nav.main-nav будет добавлен класс .is-dropdown-visible, чтобы отобразить выпадающий список.

@media only screen and (min-width: 1000px) {
	.cd-morph-dropdown .dropdown.active {
	    opacity: 1;
	    visibility: visible;
  	}
}

Фон выпадающего списка будет описан в элементе div.bg-layer.

@media only screen and (min-width: 1000px) {
	.cd-morph-dropdown .bg-layer {
    	/* morph dropdown background */
	    position: absolute;
	    top: 0;
	    left: 0;
	    height: 1px;
	    width: 1px;
	    background: #FFFFFF;
	    opacity: 0;
	    transition: opacity .3s;
	    transform-origin: top left;
  	}
  	.cd-morph-dropdown.is-dropdown-visible .bg-layer {
	    opacity: 1;
	    transition: transform .3s, opacity .3s;
  	}
}

Обработка событий

Создаём объект morphDropdown и с помощью bindEvents регистрируем события, которые будем прослушивать.

function morphDropdown( element ) {
	this.element = element;
	this.mainNavigation = this.element.find('.main-nav');
	this.mainNavigationItems = this.mainNavigation.find('.has-dropdown');
	this.dropdownList = this.element.find('.dropdown-list');
	//...

	this.bindEvents();
}

Определяем события мыши по элементам .has-dropdown и .dropdown.

morphDropdown.prototype.bindEvents = function() {
	var self = this;

	this.mainNavigationItems.mouseenter(function(event){
		//hover over one of the nav items -> show dropdown
		self.showDropdown($(this));
	}).mouseleave(function(){
		//if not hovering over a nav item or a dropdown -> hide dropdown
		if( self.mainNavigation.find('.has-dropdown:hover').length == 0 && self.element.find('.dropdown-list:hover').length == 0 ) self.hideDropdown();
	});

	//...
};

В методе showDropdown меняем высоту блока .dropdown-list для преобразования элемента .bg-layer.

morphDropdown.prototype.showDropdown = function(item) {
	var selectedDropdown = this.dropdownList.find('#'+item.data('content')),
		selectedDropdownHeight = selectedDropdown.innerHeight(),
		selectedDropdownWidth = selectedDropdown.children('.content').innerWidth(),
		selectedDropdownLeft = item.offset().left + item.innerWidth()/2 - selectedDropdownWidth/2;

	//update dropdown and dropdown background position and size
	this.updateDropdown(selectedDropdown, parseInt(selectedDropdownHeight), selectedDropdownWidth, parseInt(selectedDropdownLeft));

	//add the .active class to the selected .dropdown and .is-dropdown-visible to the .cd-morph-dropdown
	//...
};

morphDropdown.prototype.updateDropdown = function(dropdownItem, height, width, left) {
	this.dropdownList.css({
	    '-moz-transform': 'translateX(' + left + 'px)',
	    '-webkit-transform': 'translateX(' + left + 'px)',
		'-ms-transform': 'translateX(' + left + 'px)',
		'-o-transform': 'translateX(' + left + 'px)',
		'transform': 'translateX(' + left + 'px)',
		'width': width+'px',
		'height': height+'px'
	});

	this.dropdownBg.css({
		'-moz-transform': 'scaleX(' + width + ') scaleY(' + height + ')',
	    '-webkit-transform': 'scaleX(' + width + ') scaleY(' + height + ')',
		'-ms-transform': 'scaleX(' + width + ') scaleY(' + height + ')',
		'-o-transform': 'scaleX(' + width + ') scaleY(' + height + ')',
		'transform': 'scaleX(' + width + ') scaleY(' + height + ')'
	});
};

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: https://codyhouse.co/gem/stripe-navigation/
Перевел: Станислав Протасевич
Урок создан: 8 Декабря 2016
Просмотров: 3516
Правила перепечатки


5 последних уроков рубрики "CSS"

^ Наверх ^