Стековая навигация
Шаблон простой стековой навигации.
HTML
<!-- navigation --> <nav class="pages-nav"> <div class="pages-nav__item"><a class="link link--page" href="#page-home">Home</a></div> <div class="pages-nav__item"><a class="link link--page" href="#page-docu">Documentation</a></div> <div class="pages-nav__item"><a class="link link--page" href="#page-manuals">Manuals</a></div> <div class="pages-nav__item"><a class="link link--page" href="#page-software">Software</a></div> <div class="pages-nav__item"><a class="link link--page" href="#page-custom">Customization & Settings</a></div> <div class="pages-nav__item"><a class="link link--page" href="#page-training">Training</a></div> <div class="pages-nav__item pages-nav__item--small"><a class="link link--page link--faded" href="#page-buy">Where to buy</a></div> <div class="pages-nav__item pages-nav__item--small"><a class="link link--page link--faded" href="#page-blog">Blog & News</a></div> <div class="pages-nav__item pages-nav__item--small"><a class="link link--page link--faded" href="#page-contact">Contact</a></div> <div class="pages-nav__item pages-nav__item--social"> <a class="link link--social link--faded" href="#"><i class="fa fa-twitter"></i><span class="text-hidden">Twitter</span></a> <a class="link link--social link--faded" href="#"><i class="fa fa-linkedin"></i><span class="text-hidden">LinkedIn</span></a> <a class="link link--social link--faded" href="#"><i class="fa fa-facebook"></i><span class="text-hidden">Facebook</span></a> <a class="link link--social link--faded" href="#"><i class="fa fa-youtube-play"></i><span class="text-hidden">YouTube</span></a> </div> </nav> <!-- /navigation--> <!-- pages stack --> <div class="pages-stack"> <!-- page --> <div class="page" id="page-home"> <!-- page content --> </div> <!-- /page --> <div class="page" id="page-docu"> <!-- page content --> </div> <div class="page" id="page-manuals"> <!-- page content --> </div> <div class="page" id="page-software"> <!-- page content --> </div> <div class="page" id="page-custom"> <!-- page content --> </div> <div class="page" id="page-training"> <!-- page content --> </div> <div class="page" id="page-buy"> <!-- page content --> </div> <div class="page" id="page-blog"> <!-- page content --> </div> <div class="page" id="page-contact"> <!-- page content --> </div> </div> <!-- /pages-stack --> <button class="menu-button"><span>Menu</span></button> <script src="js/classie.js"></script> <script src="js/main.js"></script>
CSS
html.js, .js body { overflow: hidden; height: 100vh; } /* Pages nav */ .pages-nav { display: -webkit-flex; display: flex; -webkit-flex-wrap: wrap; flex-wrap: wrap; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; padding: 20px; text-align: center; background: #0e0f0f; } .js .pages-nav { position: absolute; top: 0; left: 0; width: 100%; height: 50vh; padding: 30px; pointer-events: none; opacity: 0; background: transparent; -webkit-transition: -webkit-transform 1.2s, opacity 1.2s; transition: transform 1.2s, opacity 1.2s; -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); -webkit-transform: translate3d(0, 150px, 0); transform: translate3d(0, 150px, 0); } .js .pages-nav--open { pointer-events: auto; opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } .pages-nav__item { width: 33%; padding: 1em; } .js .pages-nav__item { padding: 0 10%; } .pages-nav .pages-nav__item--social { width: 100%; opacity: 0; -webkit-transition: -webkit-transform 1.2s, opacity 1.2s; transition: transform 1.2s, opacity 1.2s; -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1); -webkit-transform: translate3d(0, 20px, 0); transform: translate3d(0, 20px, 0); } .pages-nav--open .pages-nav__item--social { opacity: 1; -webkit-transition-delay: 0.35s; transition-delay: 0.35s; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } .link { font-size: 0.85em; font-weight: bold; position: relative; letter-spacing: 1px; text-transform: uppercase; } .link:hover, .link:focus { color: #fff; } .link--page { display: block; color: #cecece; } .link--page:not(.link--faded)::before { content: ''; position: absolute; top: 100%; left: 50%; width: 30px; height: 2px; margin: 5px 0 0 -15px; background: #fff; -webkit-transition: -webkit-transform 0.3s; transition: transform 0.3s; -webkit-transform: scale3d(0, 1, 1); transform: scale3d(0, 1, 1); } .link--page:hover:before { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } .link--faded { color: #4f4f64; } .link--faded:hover, .link--faded:focus { color: #5c5edc; } .link--page.link--faded { font-size: 0.65em; } .link--social { font-size: 1.5em; margin: 0 0.75em; } .text-hidden { position: absolute; display: block; overflow: hidden; width: 0; height: 0; color: transparent; } /* Pages stack */ .js .pages-stack { z-index: 100; pointer-events: none; -webkit-perspective: 1200px; perspective: 1200px; -webkit-perspective-origin: 50% -50%; perspective-origin: 50% -50%; } .js .page { position: relative; z-index: 5; overflow: hidden; width: 100%; height: 100vh; pointer-events: auto; background: #2a2b30; box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); } .js .pages-stack--open .page { cursor: pointer; -webkit-transition: -webkit-transform 0.45s, opacity 0.45s; transition: transform 0.45s, opacity 0.45s; -webkit-transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1); transition-timing-function: cubic-bezier(0.6, 0, 0.4, 1); } .js .page--inactive { position: absolute; z-index: 0; top: 0; opacity: 0; } /* page content */ .info { font-size: 1.25em; max-width: 50%; margin-top: 1.5em; } .poster { position: absolute; bottom: 4vh; left: 60%; max-width: 100%; max-height: 80%; } /* Menu button */ .menu-button { position: absolute; z-index: 1000; top: 30px; left: 30px; width: 30px; height: 24px; padding: 0; cursor: pointer; border: none; outline: none; background: transparent; } .no-js .menu-button { display: none; } .menu-button::before, .menu-button::after, .menu-button span { background: #5f656f; } .menu-button::before, .menu-button::after { content: ''; position: absolute; top: 50%; left: 0; width: 100%; height: 2px; pointer-events: none; -webkit-transition: -webkit-transform 0.25s; transition: transform 0.25s; -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; } .menu-button span { position: absolute; left: 0; overflow: hidden; width: 100%; height: 2px; text-indent: 200%; -webkit-transition: opacity 0.25s; transition: opacity 0.25s; } .menu-button::before { -webkit-transform: translate3d(0, -10px, 0) scale3d(0.8, 1, 1); transform: translate3d(0, -10px, 0) scale3d(0.8, 1, 1); } .menu-button::after { -webkit-transform: translate3d(0, 10px, 0) scale3d(0.8, 1, 1); transform: translate3d(0, 10px, 0) scale3d(0.8, 1, 1); } .menu-button--open span { opacity: 0; } .menu-button--open::before { -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); } .menu-button--open::after { -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); } @media screen and (max-width: 60em) { .info { max-width: 100%; } .poster { position: relative; top: auto; left: auto; display: block; max-width: 100%; max-height: 50vh; margin: 0 0 0 50%; } .pages-nav__item { width: 50%; min-height: 20px; } .link--page { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .link--social { margin: 0 0.1em; } } @media screen and (max-width: 40em) { .js .pages-nav { display: block; padding: 10px 20px 0 20px; text-align: left; } .js .pages-nav__item { width: 100%; padding: 4px 0; } .js .pages-nav__item--small { display: inline-block; width: auto; margin-right: 5px; } .pages-nav__item--social { font-size: 0.9em; } .menu-button { top: 15px; right: 10px; left: auto; } .info { font-size: 0.85em; } .poster { margin: 1em; } }
JavaScript
/** * main.js * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2015, Codrops * http://www.codrops.com */ ;(function(window) { 'use strict'; var support = { transitions: Modernizr.csstransitions }, // transition end event name transEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend' }, transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], onEndTransition = function( el, callback ) { var onEndCallbackFn = function( ev ) { if( support.transitions ) { if( ev.target != this ) return; this.removeEventListener( transEndEventName, onEndCallbackFn ); } if( callback && typeof callback === 'function' ) { callback.call(this); } }; if( support.transitions ) { el.addEventListener( transEndEventName, onEndCallbackFn ); } else { onEndCallbackFn(); } }, // the pages wrapper stack = document.querySelector('.pages-stack'), // the page elements pages = [].slice.call(stack.children), // total number of page elements pagesTotal = pages.length, // index of current page current = 0, // menu button menuCtrl = document.querySelector('button.menu-button'), // the navigation wrapper nav = document.querySelector('.pages-nav'), // the menu nav items navItems = [].slice.call(nav.querySelectorAll('.link--page')), // check if menu is open isMenuOpen = false; function init() { buildStack(); initEvents(); } function buildStack() { var stackPagesIdxs = getStackPagesIdxs(); // set z-index, opacity, initial transforms to pages and add class page--inactive to all except the current one for(var i = 0; i < pagesTotal; ++i) { var page = pages[i], posIdx = stackPagesIdxs.indexOf(i); if( current !== i ) { classie.add(page, 'page--inactive'); if( posIdx !== -1 ) { // visible pages in the stack page.style.WebkitTransform = 'translate3d(0,100%,0)'; page.style.transform = 'translate3d(0,100%,0)'; } else { // invisible pages in the stack page.style.WebkitTransform = 'translate3d(0,75%,-300px)'; page.style.transform = 'translate3d(0,75%,-300px)'; } } else { classie.remove(page, 'page--inactive'); } page.style.zIndex = i < current ? parseInt(current - i) : parseInt(pagesTotal + current - i); if( posIdx !== -1 ) { page.style.opacity = parseFloat(1 - 0.1 * posIdx); } else { page.style.opacity = 0; } } } // event binding function initEvents() { // menu button click menuCtrl.addEventListener('click', toggleMenu); // navigation menu clicks navItems.forEach(function(item) { // which page to open? var pageid = item.getAttribute('href').slice(1); item.addEventListener('click', function(ev) { ev.preventDefault(); openPage(pageid); }); }); // clicking on a page when the menu is open triggers the menu to close again and open the clicked page pages.forEach(function(page) { var pageid = page.getAttribute('id'); page.addEventListener('click', function(ev) { if( isMenuOpen ) { ev.preventDefault(); openPage(pageid); } }); }); // keyboard navigation events document.addEventListener( 'keydown', function( ev ) { if( !isMenuOpen ) return; var keyCode = ev.keyCode || ev.which; if( keyCode === 27 ) { closeMenu(); } } ); } // toggle menu fn function toggleMenu() { if( isMenuOpen ) { closeMenu(); } else { openMenu(); isMenuOpen = true; } } // opens the menu function openMenu() { // toggle the menu button classie.add(menuCtrl, 'menu-button--open') // stack gets the class "pages-stack--open" to add the transitions classie.add(stack, 'pages-stack--open'); // reveal the menu classie.add(nav, 'pages-nav--open'); // now set the page transforms var stackPagesIdxs = getStackPagesIdxs(); for(var i = 0, len = stackPagesIdxs.length; i < len; ++i) { var page = pages[stackPagesIdxs[i]]; page.style.WebkitTransform = 'translate3d(0, 75%, ' + parseInt(-1 * 200 - 50*i) + 'px)'; // -200px, -230px, -260px page.style.transform = 'translate3d(0, 75%, ' + parseInt(-1 * 200 - 50*i) + 'px)'; } } // closes the menu function closeMenu() { // same as opening the current page again openPage(); } // opens a page function openPage(id) { var futurePage = id ? document.getElementById(id) : pages[current], futureCurrent = pages.indexOf(futurePage), stackPagesIdxs = getStackPagesIdxs(futureCurrent); // set transforms for the new current page futurePage.style.WebkitTransform = 'translate3d(0, 0, 0)'; futurePage.style.transform = 'translate3d(0, 0, 0)'; futurePage.style.opacity = 1; // set transforms for the other items in the stack for(var i = 0, len = stackPagesIdxs.length; i < len; ++i) { var page = pages[stackPagesIdxs[i]]; page.style.WebkitTransform = 'translate3d(0,100%,0)'; page.style.transform = 'translate3d(0,100%,0)'; } // set current if( id ) { current = futureCurrent; } // close menu.. classie.remove(menuCtrl, 'menu-button--open'); classie.remove(nav, 'pages-nav--open'); onEndTransition(futurePage, function() { classie.remove(stack, 'pages-stack--open'); // reorganize stack buildStack(); isMenuOpen = false; }); } // gets the current stack pages indexes. If any of them is the excludePage then this one is not part of the returned array function getStackPagesIdxs(excludePageIdx) { var nextStackPageIdx = current + 1 < pagesTotal ? current + 1 : 0, nextStackPageIdx_2 = current + 2 < pagesTotal ? current + 2 : 1, idxs = [], excludeIdx = excludePageIdx || -1; if( excludePageIdx != current ) { idxs.push(current); } if( excludePageIdx != nextStackPageIdx ) { idxs.push(nextStackPageIdx); } if( excludePageIdx != nextStackPageIdx_2 ) { idxs.push(nextStackPageIdx_2); } return idxs; } init(); })(window);
Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://tympanus.net/codrops/2015/10/21/page-stack-navigation/
Перевел: Станислав Протасевич
Урок создан: 26 Октября 2015
Просмотров: 9097
Правила перепечатки
5 последних уроков рубрики "CSS"
-
Забавные эффекты для букв
Небольшой эффект с интерактивной анимацией букв.
-
Реализация забавных подсказок
Небольшой концепт забавных подсказок, которые реализованы на SVG и anime.js. Помимо особого стиля в примере реализована анимация и трансформация графических объектов.
-
Анимированные буквы
Эксперимент: анимированные SVG буквы на базе библиотеки anime.js.
-
Солнцезащитные очки от первого лица
Прикольный эксперимент веб страницы отображение которой осуществляется “от первого лица” через солнцезащитные очки.
-
Раскрывающаяся навигация
Экспериментальный скрипт раскрывающейся навигации.