Как показать меню сайта при прокрутке вверх

02.09.2019

У каждого веб-сайта есть меню, которое как правило располагается в шапке. Для удобного пользовательского опыта мы должны давать возможность быстро перемещаться по сайту и часто для этого используется меню, прилипающее к верхнему краю экрана. Но что если мы хотим чтобы пользователь не отвлекался на лишние элементы, а меню не занимало ценное на странице место.

Сделаем так, чтобы при скролле вверх наше меню плавно появлялось, а при прокрутке вниз – плавно скрывалось. Можно частично использовать основу из статьи про то, как сделать плавающее меню на Javascript:

<header id="header" class="header"></header>
<nav id="nav" class="nav">
  <ul class="nav-wr">
    <li class="nav-item">
      <a class="nav-link" href="">
        <span>Menu item</span>
      </a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="">
        <span>Menu item</span>
      </a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="">
        <span>Menu item</span>
      </a>
    </li>
  </ul>
</nav>
<main id="main" class="main">Content</main>

CSS стили:

/* Сбросим дефолтные отступы */
body{
  margin: 0;
  padding: 0;
}

.header{
  background: #FFFACD;
  width: 100%;  
  height: 100px;
}
.nav{
  background: #87CEEB;
  width: 100%;
  height: 50px;
  overflow: hidden;
  display: flex;
  justify-content: space-around;
}
.main{
  background: #AFEEEE;
  width: 100%;
  height: 150vh;
  display: block;
}
.nav-wr{
  display: flex;
  list-style: none;
  padding: 0;
  margin: 0;
}
.nav-item{
  margin: 0 10px;
  display: flex;
}
.nav-link{
  display: flex;
  align-items: center;
  text-decoration: none;
}

.menu-sticky-hidden{
  position: fixed;
  top: 0;
  height: 0;
  transition: none;
}
.menu-sticky-hidden + .main{
  padding-top: 50px;
}

.menu-sticky-visible{
  position: fixed;
  top: 0;
  height: 50px;
  transition: all ease-out 0.2s;
}
.menu-sticky-visible + .main{
  padding-top: 50px;
}

.menu-animation{
  transition: all ease-out 0.2s;
}

Сложность задачи заключается в том, чтобы сделать все этапы появления/скрытия меню плавными с помощью css-свойства transition. Получается, что для одного и того же интервала при разном направлении прокрутки нам необходимо задавать разные значения position и стили с определенной специфичностью.

Для этого будем присваивать меню три CSS класса в зависимости от состояния прокрутки в данный момент:

  • .menu-animation - будет отвечать за наличие анимации у меню, чтобы меню не дергалось при самом первом скролле, когда мы присваиваем ему значение 0;
  • .menu-sticky-hidden - за позиционирование меню и его высоту при прокрутке вниз;
  • .menu-sticky-visible - за позиционирование меню и его высоту при прокрутке вверх.
var nav = document.getElementById("nav");
var header = document.getElementById("header");
var headerHeight = header.clientHeight;
var lastTopOffset = 0;

window.onscroll = function() {
  var pageOffset = window.pageYOffset;

  if ( pageOffset > (headerHeight + 70) ) {
    nav.classList.add("menu-animation");
  } else {
    nav.classList.remove("menu-animation");
  }

  if ( pageOffset > (headerHeight + 50) ) {
    nav.classList.add("menu-sticky-hidden");
  } else {
    nav.classList.remove("menu-sticky-hidden");
  }

  if (pageOffset < lastTopOffset) {
    if ( pageOffset > headerHeight ) {
      nav.classList.add("menu-sticky-visible");
    } else {
      nav.classList.remove("menu-sticky-visible");
    }
  } else {
    nav.classList.remove("menu-sticky-visible");
  }

  lastTopOffset = pageOffset;
};

Значение 50 - это высота нашего меню, значение 70 - это высота меню + 20 условных пикселей, которые нужны для того, чтобы при резкой прокрутке вниз CSS класс .menu-sticky-hidden успел добавиться в меню раньше .menu-animation и меню не сделало transition от 50 до 0 пикселей своей высоты.

« список статей