Анимированное меню на границах страницы

Недавно мы натолкнулись на интересное меню на сайте UI8. Поэтому сегодня рассмотрим как можно реализовать подобные примеры для своих сайтов.

HTML
Навигация будет состоять из ненумерованного списка, помещённого в элемент nav. Через атрибут класс передаём какая иконка должна быть прикреплена к элементу:

Код
<nav id="bt-menu" class="bt-menu">
  <a href="#" class="bt-menu-trigger"><span>Menu</span></a>
  <ul>
  <li><a href="#" class="bt-icon icon-zoom">Zoom</a></li>
  <li><a href="#" class="bt-icon icon-refresh">Refresh</a></li>
  <li><a href="#" class="bt-icon icon-lock">Lock</a></li>
  <li><a href="#" class="bt-icon icon-speaker">Sound</a></li>
  <li><a href="#" class="bt-icon icon-star">Favorite</a></li>
  </ul>
</nav>

Теперь давайте оформим всё это дело.

CSS

Обратите внимание, что код с браузерными префиксами, можете найти в исходниках. Воспользуемся свойством box-sizing:

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

Зададим общие стили для body и основного контейнера:

Код
body {
  background: #04a466;
}

.container {
  padding: 80px;
}

Внутренние отступы можем использовать для расширения нужного нам пространства.

Основной элемент навигации будет располагаться фиксировано в зависимости от того, какой пример мы запустим. При раскрытии меню, меняем ширину рамки. Сначала высота рамки будет равна 0. Далее мы её расширим с задержкой в 0.3 сек:

Код
.bt-menu {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 0;
  border-width: 0px;
  border-style: solid;
  border-color: #333;
  background-color: rgba(0,0,0,0);
  transition: border-width 0.3s, background-color 0.3s, height 0s 0.3s;
}

При раскрытии меню меняем высоту и ставим значение 100%, а рамку смещаем на 90px влево и на 30px со всех других сторон. Цвет фона выставим в формате RGBA:

Код
.bt-menu.bt-menu-open {
  height: 100%;
  border-width: 30px 30px 30px 90px;
  background-color: rgba(0,0,0,0.3);
  transition: border-width 0.3s, background-color 0.3s;
}

Далее применим один финт. Через JavaScript добавим невидимый элемент при клике на который, поставленная нами рамка будет исчезать. Он будет расширен на всю страниц

Код
.bt-overlay {
  position: absolute;
  width: 100%;
}

При открытии меню, расширяем данный элемент:

Код
.bt-menu-open .bt-overlay {
  height: 100%;
}

.bt-menu-trigger {
  position: fixed;
  top: 15px;
  left: 20px;
  display: block;
  width: 50px;
  height: 50px;
  cursor: pointer;
}

.bt-menu-trigger span {
  position: absolute;
  top: 50%;
  left: 0;
  display: block;
  width: 100%;
  height: 4px;
  margin-top: -2px;
  background-color: #fff;
  font-size: 0px;
  user-select: none;
  transition: background-color 0.3s;
}

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

Код
.bt-menu-open .bt-menu-trigger span {
  background-color: transparent;
}

Псевдо-элементы расположим абсолютно и их высота будет такой же как у родительского элемента - 100%:

Код
.bt-menu-trigger span:before,
.bt-menu-trigger span:after {
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  background: #fff;
  content: '';
  transition: transform 0.3s;
}

Для того позиционирования, воспользуемся свойством translateY:

Код
.bt-menu-trigger span:before {
  transform: translateY(-250%);
}

.bt-menu-trigger span:after {
  transform: translateY(250%);
}

.bt-menu-open .bt-menu-trigger span:before {
  transform: translateY(0) rotate(45deg);
}

.bt-menu-open .bt-menu-trigger span:after {
  transform: translateY(0) rotate(-45deg);
}

Ненумерованные списки с иконками расположим фиксированно и поместим в левую часть экрана:

Код
.bt-menu ul {
  position: fixed;
  top: 75px;
  left: 0;
  margin: 0;
  padding: 0;
  width: 90px;
  list-style: none;
  backface-visibility: hidden;
}

Давайте зададим элементам меню блочный вид расположения display: block, а так же ширину:

Код
.bt-menu ul li,
.bt-menu ul li a {
  display: block;
  width: 100%;
  text-align: center;
}

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

Код
.bt-menu ul li {
  padding: 16px 0;
  opacity: 0;
  visibility: hidden;
  transition: transform 0.3s, opacity 0.2s, visibility 0s 0.3s;
}

Теперь давайте расположим все элементы меню по центру слева , до тех пор пока они не отображаемые (-100% на оси Y):

Код
.bt-menu ul li:first-child {
  transform: translate3d(-100%,200%,0);
}

.bt-menu ul li:nth-child(2) {
  transform: translate3d(-100%,100%,0);
}

.bt-menu ul li:nth-child(3) {
  transform: translate3d(-100%,0,0);
}

.bt-menu ul li:nth-child(4) {
  transform: translate3d(-100%,-100%,0);
}

.bt-menu ul li:nth-child(5) {
  transform: translate3d(-100%,-200%,0);
}

При открытии меню, элементы списка станут видимыми, а затем применяем эффект плавного появления. Так же изменим значение transform до 0, для достижения 3d эффекта:

Код
.bt-menu.bt-menu-open ul li {
  visibility: visible;
  opacity: 1;
  transition: transform 0.3s, opacity 0.3s;
  transform: translate3d(0,0,0);
}

Теперь займёмся ссылками. В качестве шрифтов будем использовать иконки. Задаём размер шрифта, равный 0, и делаем его невидимым:

Код
.bt-menu ul li a {
  display: block;
  outline: none;
  color: transparent;
  text-decoration: none;
  font-size: 0px;
}

Сбросим размер текста псевдо-элементов, которые содержат иконки. Значения em тут работать не будут, поэтому задаём размеры в пикселях:

Код
.bt-menu ul li a:before {
  color: #04a466;
  font-size: 48px;
  transition: color 0.2s;
}

При наведении мыши сделаем их цвет белым:

Код
.bt-menu ul li a:hover:before,
.bt-menu ul li a:focus:before {
  color: #fff;
}

Сделаем иконки чуть меньше, если пользователь просматривает сайт через мобильное устройство:

Код
@media screen and (max-height: 31.125em) {
  .bt-menu ul li a:before {
  font-size: 32px;
  }
}

о стилями всё. Приступаем к JavaScript.

JAVASCRIPT

Наш скрипт очень простой; при клике по ссылке, мы прикрепляем или открепляем классы bt-menu-open и bt-menu-close.

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

Код
(function() {
  function mobilecheck() {
  var check = false;
  (function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
  }

  function init() {

  var menu = document.getElementById( 'bt-menu' ),
  trigger = menu.querySelector( 'a.bt-menu-trigger' ),
  // тип события (если мобильное устройство, то используются события нажатий)
  eventtype = mobilecheck() ? 'touchstart' : 'click',
  resetMenu = function() {
  classie.remove( menu, 'bt-menu-open' );
  classie.add( menu, 'bt-menu-close' );
  },
  closeClickFn = function( ev ) {
  resetMenu();
  overlay.removeEventListener( eventtype, closeClickFn );
  };

  var overlay = document.createElement('div');
  overlay.className = 'bt-overlay';
  menu.appendChild( wrapper );

  trigger.addEventListener( eventtype, function( ev ) {
  ev.stopPropagation();
  ev.preventDefault();

  if( classie.has( menu, 'bt-menu-open' ) ) {
  resetMenu();
  }
  else {
  classie.remove( menu, 'bt-menu-close' );
  classie.add( menu, 'bt-menu-open' );
  overlay.addEventListener( eventtype, closeClickFn );
  }
  });

  }

  init();

})();

Вот и всё! Я надеюсь, данный урок будет вам полезен!

  • FalleN

  • 3512

  • 1

  • 213

Ссылки на статью:

Похожие статьи: