Как создать фиксированный хедер с анимацией во время прокрутки страницы

Как создать фиксированный хедер с анимацией во время прокрутки страницы

От автора: в этом уроке мы узнаем, как создать шаблон, который сейчас часто встречается на сайтах: фиксированный хедер, который плавно сжимается при прокрутке страницы. Начнем со структуры, а затем при помощи CSS и обычного JS заставим всю эту конструкцию работать. В самом конце мы коротко пробежимся по тому, как можно оптимизировать код, а также обсудим проблемы, которые встречаются у этого шаблона на сенсорных устройствах.

Чтобы вы поняли, что мы сегодня будем создавать, посмотрите демо ниже (или полноэкранную версию):

HTML разметка

Начнем мы со следующей разметки – хедер с тегом nav внутри и другими элементами:

<header>
  <nav>
    <h1>
      <a href="" class="logo">Logo</a>
    </h1>
    <ul>
      <li>
        <a href="">About</a>
      </li>
      <li>
        <a href="">Services</a>
      </li>
      <li>
        <a href="">Portfolio</a>
      </li>
      <li>
        <a href="">Contact</a>
      </li>
    </ul>
    <button class="toggle-menu" aria-label="Responsive Navigation Menu">☰</button>
  </nav>
</header>
 
<main>
  <!-- контент -->
</main>

В элементе nav, который является частью хедера, содержатся еще три элемента: логотип, основное меню и кнопка плейсхолдер, по которой срабатывает адаптивное меню (на экранах уже 1061px). Обратите внимание: По клику на эту кнопку ничего не произойдет. Создание адаптивного меню не входит в тему урока.

Первичные стили CSS

Давайте взглянем на стили CSS и заставим нашу разметку двигаться:

header {
  position: fixed;
  top: 0;
  width: 100%;
  padding: 20px;
  box-sizing: border-box;
  background: #DD3543;
}
 
nav {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  transition: align-items .2s;
}
 
.logo {
  font-size: 2rem;
  display: inline-block;
  padding: 20px 30px;
  background: #F35B66;
  color: #fff;
  margin: 50px 0 0 50px;
  transition: all .2s;
}
 
ul {
  display: flex;
  margin: 50px 50px 0 0;
  padding: 0;
  transition: margin .2s;
}
 
li:not(:last-child) {
  margin-right: 20px;
}
 
li a {
  display: block;
  padding: 10px 20px;
}
 
.toggle-menu {
  display: none;
  font-size: 2rem;
  color: #fff;
  margin: 10px 10px 0 0;
  transition: margin .2s;
}
 
main {
  display: block;
  padding: 0 20px;
}

Краткое объяснение самых важных правил:

элемент header имеет фиксированную позицию;

для позиционирования элемента nav используется flexbox;

логотипу заданы правила margin-top: 50px и margin-left: 50px, а также padding: 20px 30px;

главное меню расположено напротив логотипа, и ему заданы свойства margin-top: 50px и margin-right: 50px;

адаптивная кнопка скрыта и становится видима только, когда ширина окна меньше 1061px. Кроме того, заданы верхний и правый margin’ы в 10px;

свойствам, чье значение в будущем изменится, мы применили свойство transition. Таким образом достигается плавный переход от первичного к конечному состоянию.

С этими стилями хедер выглядит следующим образом:

Анимация хедера

Мы построили базовую структуру хедера. Теперь необходимо обсудить следующие шаги:

элемент main должен быть расположен прямо под хедером. Не забывайте, что у хедера задано свойство positioned: fixed, из-за чего он расположен сверху элемента main;

анимация к хедеру применяется во время прокрутки страницы вниз.

Чтобы решить первую задачу, к элементу main необходимо добавить свойство padding-top, значение которого должно быть равно высоте хедера. В нашем случае у нас нет точной фиксированной высоты хедера, поэтому для ее вычисления нам понадобится JS. После вычисления высоту уже можно добавлять соответствующий padding элементу main. Для решения второй задачи мы сделаем следующее:

вытягиваем количество пикселей, на которое был прокручен документ;

если число больше 150px, добавляем класс scroll к хедеру.

JavaScript

Ниже представлен необходимый JS код. Начнем мы с объявления парочки переменных, вычислим высоту хедера и добавим это значение в свойстве padding-top в элемент main:

var m = document.querySelector("main"),
    h = document.querySelector("header"),
    hHeight;
 
function setTopPadding() {
  hHeight = h.offsetHeight;
  m.style.paddingTop = hHeight + "px";
}

Для этой демонстрации мы используем свойство offsetHeight, чтобы вытянуть высоту хедера. Не забывайте, что мы точно так же могли использовать метод getBoundingClientRect(). Стоит отметить, что данный метод может вернуть дробное значение. Теперь по поводу события прокрутки:

function onScroll() {
  window.addEventListener("scroll", callbackFunc);
  function callbackFunc() {
    var y = window.pageYOffset;
    if (y > 150) {
      h.classList.add("scroll");
    } else {
      h.classList.remove("scroll");
    }
  }
}

Для вычисления количества прокрученных в документе пикселей мы используем свойство pageYOffset объекта window. Данное свойство не работает в старых версиях IE (<9). Если же вам нужна поддержка этих версий, есть способ.

Для присвоения и удаления класса scroll в хедере мы используем свойство classList. Данное свойство поддерживается не во всех браузерах. Если вам нужна поддержка этих браузеров, можете воспользоваться полифилами classList.js и classie.js. В рамках нашего примера мы могли бы использовать свойство className для изменения одного класса, но в реальной жизни это далеко неидеальное решение (если классов много). В общем, функцию мы вызываем в двух случаях:

после загрузки страницы;

при изменении размера окна браузера.

window.onload = function() {
  setTopPadding();
  onScroll();
};
 
window.onresize = function() {
  setTopPadding();
};

Как только мы докручиваем до 150px, добавляются дополнительные CSS правила:

.scroll {
  box-shadow: 0 7px 0 0 rgba(0, 0, 0, .1);
}
 
.scroll .logo {
  padding: 10px 20px;
  font-size: 1.5rem;
}
 
.scroll nav {
  align-items: center;
}
 
.scroll .logo,
.scroll ul,
.scroll .toggle-menu {
  margin: 0;
}

Мы делаем следующие изменения:

добавляем светло-серый box-shadow хедеру;

уменьшаем padding и font-size логотипа;

изменяем выравнивание флекс элементов вдоль оси;

удаляем margin у логотипа, меню и адаптивной кнопки.

Вышеописанный правила делает хедер таким:

Добавляем адаптивность

Как мы упоминали в предыдущем разделе, когда ширина окна становится меньше 1061px, мы прячем меню и показываем адаптивную кнопку (которая ничего не делает). Также вносятся дополнительные изменения в необходимые элементы. Ниже показан адаптивный хедер в первичном состоянии:

Необходимые CSS правила:

@media screen and (max-width: 1060px) {
  header {
    padding: 10px;
  }
  nav {
    align-items: center;
  }
  ul {
    display: none;
  }
  .logo {
    font-size: 1.8rem;
    margin: 10px 0 0 10px;
  }
  .toggle-menu {
    display: block;
  }
}

А тут показан хедер после анимации:

Вопросы производительности

Мы добились, чтобы наш хедер вел себя, так как было запланировано. Теперь давайте перейдем к следующему шагу и обсудим вопрос производительности.

В нашем примере код, отвечающий за анимацию хедера (т.е. callbackFunc), запускается по событию scroll. То есть код может вызываться сотни раз или даже больше. Такой подход может сильно повлиять на производительность, особенно когда в функции callbackFunc хранится много кода, который должен выполняться при прокрутке страницы вверх и винз. В нашем случае анимация простая, но представьте реальный сценарий, где мы хотим сделать более сложную анимацию. Например, изменить позицию элемента и т.д.

Что же можно сделать? Есть множество возможных решений, но сейчас давайте коротко обсудим одно из них. Необходимо добиться, чтобы наша функция выполнялась максимум один раз за 200 миллисекунд (значение произвольное). Для этого нам понадобится JS библиотека Lodash, в которой есть функция throttle.

Во-первых, необходимо подключить библиотеку (к счастью, есть возможность подключить только нужную функцию). Во-вторых, необходимо заменить строку:

window.addEventListener("scroll", callbackFunc);

на:

window.addEventListener("scroll", _.throttle(callbackFunc, 200));

Чтобы уловить разницу, проведем простой тест. Создадим счетчик, который увеличивается по инкременту каждый раз, когда срабатывает функция callbackFunc.

Теперь покрутите страницу вниз и вверх. Вы заметите, что счетчик увеличивается примерно каждые 200ms. А теперь повторите процесс, но уже без библиотеки Lodash. Вы увидите, что счетчик стал увеличиваться гораздо быстрее.

В нашем простом примере такая оптимизация не нужна, но вам стоит помнить о ней, когда работаете с затратными и повторяющимися задачами.

Точно так же можно было бы оптимизировать обработчик события resize.

Поддержка в браузерах

Данный эффект работает в большинстве последних версий браузеров и устройств. Тем не менее, с мобильными устройствами возникают проблемы (например, iOS). Это происходит из-за того, что событие scroll по-разному ведет себя в браузерах на компьютерах и мобильных устройствах. К примеру, в браузере компьютера событие scroll запускается непрерывно, а на iPad только после того, как был сделан свайп и убран палец с экрана.

Зная об этих проблемах, вы должны сами решать, на каких страницах данный шаблон можно использовать, а на каких нет.

Заключение

В этом уроке мы создали фиксированный хедер с анимацией, которая срабатывает во время прокрутки страницы. Надеюсь, вам понравилось демо, и вы используете эти наработки в своих будущих проектах!

Редакция: Автор: George Martsoukos

Источник: http://webdesign.tutsplus.com/

Редакция: Команда webformyself.

Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

Получить

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree