Як створити фіксований хедер з анімацією під час прокручування сторінки

18

Від автора: у цьому уроці ми дізнаємося, як створити шаблон, який зараз часто зустрічається на сайтах: фіксований хедер, який плавно стискається при прокручуванні сторінки. Почнемо зі структури, а потім за допомогою CSS і звичайного JS змусимо всю цю конструкцію працювати. У самому кінці ми коротко пробіжимося по тому, як можна оптимізувати код, а також обговоримо проблеми, які зустрічаються у цього шаблону на сенсорних пристроях.

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

HTML-розмітка

Почнемо ми з наступного розмітки – хедер з тегом nav всередині і іншими елементами:

Logo

  • About
  • Services
  • Portfolio
  • Contact

В елементі 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. Крім того, задані верхній і правий магдіп’и в 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.5 rem;
}
.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.8 rem;
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 тільки після того, як був зроблений свайп і прибраний палець з екрана.

Знаючи про ці проблеми, ви повинні самі вирішувати, на яких сторінках даний шаблон можна використовувати, а які ні.

Висновок

У цьому уроці ми створили фіксований хедер з анімацією, яка спрацьовує під час прокручування сторінки. Сподіваюся, вам сподобалося демо, і ви використовуєте ці напрацювання у своїх майбутніх проектах!