Изменение цвета фона при прокрутке с помощью JavaScript
В последнее время анимация прокрутки становится все более популярной тенденцией, особенно на целевых страницах SaaS и современных технологических стартапов. Эти анимации призваны украсить пользовательский интерфейс, если только они грамотно закодированы и не слишком навязчивы для конечного пользователя.
Ранее мы уже создавали учебные пособия по этой теме, например, по анимации "водопада" карточек при прокрутке или по градиентному раскрытию текста. Сегодня мы добавим к этому списку еще один пример: изменение цвета фона страницы при прокрутке.
Этот эффект позволит придать дизайну динамичность и сделать каждый раздел уникальным.
Структурирование HTML
В этом демонстрационном примере мы создадим элемент <main>
с четырьмя секциями, каждая из которых будет связана с отдельным цветом из палитры Tailwind: Sky 200, Purple 200, Pink 200 и Emerald 200.
Чтобы обеспечить плавные цветовые переходы, мы не будем напрямую применять цвета фона к отдельным разделам. Вместо этого мы воспользуемся API Intersection Observer для определения доминирующей секции и применим соответствующий цвет фона к основному контейнеру.
Вот основная структура HTML:
<main class="relative min-h-screen flex flex-col bg-sky-200 overflow-hidden">
<div class="w-full max-w-5xl mx-auto px-4 md:px-6">
<div class="pt-6 pb-12 md:pt-10 md:pb-20">
<!-- Sky section -->
<section>
<!-- ... content ... -->
</section>
<!-- Purple section -->
<section>
<!-- ... content ... -->
</section>
<!-- Pink section -->
<section>
<!-- ... content ... -->
</section>
<!-- Emerald section -->
<section>
<!-- ... content ... -->
</section>
</div>
</div>
</main>
Мы установили цвет фона элемента <main>
по умолчанию на Sky 200 (bg-sky-200
, это цвет первой секции) и убедились, что он заполняет по крайней мере высоту области просмотра с помощью min-h-screen
.
Создание JS-класса
Создадим в корне проекта файл bg-scroll.js
и включим его в наш HTML-документ:
<script src="./bg-scroll.js"></script>
В этом файле мы определим класс с именем BgScroll
, который будет содержать метод init
для инициализации наблюдателя. Вот код для начала:
class BgScroll {
constructor(element) {
this.element = element;
this.init();
}
init() {
}
}
// Init BgScroll
const el = document.querySelector('[data-bg-scroll]');
new BgScroll(el);
В конце файла мы указываем, как инициализировать класс, добавляя атрибут data-bg-scroll
к элементу <main>
в HTML:
<main class="relative min-h-screen flex flex-col bg-sky-200 overflow-hidden" data-bg-scroll>
Создание наблюдателя
Теперь напишем код для инициализации наблюдателя:
class BgScroll {
constructor(element) {
this.element = element;
this.sections = this.element.querySelectorAll('section');
this.observeSection = this.observeSection.bind(this);
this.init();
}
observeSection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log(entry.target);
}
});
}
init() {
const observer = new IntersectionObserver(this.observeSection, { rootMargin: '-50% 0% -50% 0%' });
this.sections.forEach(section => {
observer.observe(section);
});
}
}
// Init BgScroll
const el = document.querySelector('[data-bg-scroll]');
new BgScroll(el);
В конструкторе мы создали новый экземпляр с именем sections
, который содержит массив всех секций внутри основного элемента. В методе init()
мы проходим по этому массиву и создаем нового наблюдателя для каждой секции.
Первым аргументом IntersectionObserver
является обратный вызов, который будет выполняться каждый раз, когда секция входит или выходит из области просмотра (т.е. observeSection
). Второй аргумент - объект options
, который содержит свойство rootMargin
. Используя значения -50% 0% -50% 0%
, мы указываем IntersectionObserver
на то, что обратный вызов должен срабатывать, когда секция пересекает воображаемую горизонтальную линию, расположенную на расстоянии 50% от верхней границы области просмотра.
Для тестирования мы добавили console.log
внутри метода observeSection
, чтобы определить доминирующую секцию при прокрутке.
Изменение цвета фона
Теперь, когда мы знаем, какой раздел является доминирующим, мы можем применить соответствующий цвет фона к элементу <main>
.
Для этого мы определим цвет фона каждой секции с помощью атрибута data-bg-color
и класса Tailwind соответствующего цвета фона:
<main class="relative min-h-screen flex flex-col bg-sky-200 overflow-hidden" data-bg-scroll>
<div class="w-full max-w-5xl mx-auto px-4 md:px-6">
<div class="pt-6 pb-12 md:pt-10 md:pb-20">
<!-- Sky section -->
<section data-bg-class="bg-sky-200">
<!-- ... content .... -->
</section>
<!-- Purple section -->
<section data-bg-class="bg-purple-200">
<!-- ... content .... -->
</section>
<!-- Pink section -->
<section data-bg-class="bg-pink-200">
<!-- ... content .... -->
</section>
<!-- Emerald section -->
<section data-bg-class="bg-emerald-200">
<!-- ... content .... -->
</section>
</div>
</div>
</main>
Теперь внутри метода observeSection
мы можем получить значение атрибута entry.target.dataset.bgClass
и применить его к основному элементу:
class BgScroll {
constructor(element) {
this.element = element;
this.sections = this.element.querySelectorAll('section');
this.observeSection = this.observeSection.bind(this);
this.init();
}
observeSection(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Remove all bg classes
this.element.classList.forEach(className => {
if (className.startsWith('bg-')) {
this.element.classList.remove(className);
}
});
// Add the proper bg class
this.element.classList.add(entry.target.dataset.bgClass);
}
});
}
init() {
const observer = new IntersectionObserver(this.observeSection, { rootMargin: '-50% 0% -50% 0%' });
this.sections.forEach(section => {
observer.observe(section);
});
}
}
// Init BgScroll
const el = document.querySelector('[data-bg-scroll]');
new BgScroll(el);
И, как вы уже догадались, мы также удаляем все классы, начинающиеся с bg-
, чтобы обеспечить применение только одного фонового класса.
Добавление анимации затухания
Для завершения эффекта мы добавим анимацию затухания к изменению цвета фона. Для этого достаточно добавить класс transition-colors
в элемент <main>
таким образом:
<main class="relative min-h-screen flex flex-col bg-sky-200 transition-colors duration-700 overflow-hidden" data-bg-scroll>
Мы также добавили класс duration-700
, позволяющий увеличить длительность анимации для получения более плавного эффекта.
Заключение
Создать этот динамический фоновый эффект с помощью Intersection Observer невероятно просто. Он занимает всего около 30 строк JavaScript, и никаких внешних библиотек не требуется.
Не стесняйтесь проводить собственные эксперименты и изменять код в соответствии со своими потребностями.