CSS-анимации при смене роутов

При работе с библиотекой Navigo для управления маршрутизацией в JavaScript важным аспектом является создание плавных переходов между страницами или секциями приложения. CSS-анимации позволяют добавлять визуальные эффекты при смене роутов, улучшая пользовательский опыт без использования громоздких JavaScript-фреймворков.

Настройка структуры проекта

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

<div id="app">
    <div class="page" id="home">Главная страница</div>
    <div class="page" id="about">О нас</div>
    <div class="page" id="contact">Контакты</div>
</div>

В CSS следует задать базовые стили для страниц:

.page {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    opacity: 0;
    transition: opacity 0.5s ease, transform 0.5s ease;
    transform: translateX(100%);
}

.page.active {
    opacity: 1;
    transform: translateX(0);
}

Ключевые моменты:

  • Использование position: absolute позволяет накладывать страницы друг на друга и управлять их видимостью через opacity и transform.
  • Свойства transition задают длительность и плавность анимации.

Инициализация Navigo

Создание экземпляра Navigo и настройка маршрутов:

import Navigo from 'navigo';

const router = new Navigo('/', { hash: true });

function showPage(id) {
    const pages = document.querySelectorAll('.page');
    pages.forEach(page => page.classList.remove('active'));
    const activePage = document.getElementById(id);
    if (activePage) {
        activePage.classList.add('active');
    }
}

router.on({
    '/': () => showPage('home'),
    '/about': () => showPage('about'),
    '/contact': () => showPage('contact')
}).resolve();

Ключевые моменты:

  • Метод on принимает объект с маршрутами и соответствующими колбэками.
  • Функция showPage управляет добавлением класса active, который инициирует CSS-анимацию.

Плавная смена страниц с анимацией выхода

Чтобы страницы не просто появлялись мгновенно, можно добавить анимацию выхода для текущей страницы:

.page.exit {
    opacity: 0;
    transform: translateX(-100%);
}

Модификация функции показа страницы:

function transitionToPage(id) {
    const current = document.querySelector('.page.active');
    if (current) {
        current.classList.add('exit');
        current.addEventListener('transitionend', () => {
            current.classList.remove('active', 'exit');
            const next = document.getElementById(id);
            next.classList.add('active');
        }, { once: true });
    } else {
        const next = document.getElementById(id);
        next.classList.add('active');
    }
}

Особенности реализации:

  • Класс exit инициирует анимацию ухода страницы.
  • Событие transitionend гарантирует, что новая страница появляется только после завершения анимации предыдущей.
  • Опция { once: true } предотвращает множественные вызовы обработчика.

Использование анимаций с различными эффектами

Можно комбинировать разные CSS-свойства для сложных эффектов: сдвиг, масштабирование, поворот, изменение прозрачности. Пример:

.page.slide-in {
    transform: translateX(100%) scale(0.9);
}

.page.slide-in.active {
    transform: translateX(0) scale(1);
    opacity: 1;
}

.page.slide-out {
    transform: translateX(-100%) scale(0.9);
    opacity: 0;
}

И адаптация JavaScript-функции:

function animatePage(id) {
    const current = document.querySelector('.page.active');
    if (current) {
        current.classList.add('slide-out');
        current.addEventListener('transitionend', () => {
            current.classList.remove('active', 'slide-out');
            const next = document.getElementById(id);
            next.classList.add('slide-in', 'active');
            requestAnimationFrame(() => {
                next.classList.remove('slide-in');
            });
        }, { once: true });
    } else {
        const next = document.getElementById(id);
        next.classList.add('slide-in', 'active');
        requestAnimationFrame(() => {
            next.classList.remove('slide-in');
        });
    }
}

Ключевые моменты:

  • Использование requestAnimationFrame обеспечивает корректный запуск CSS-анимации после добавления класса.
  • Разделение классов для входа (slide-in) и выхода (slide-out) позволяет легко менять эффекты без дублирования кода.

Работа с динамическим контентом

Если контент загружается динамически через AJAX, важно добавить класс active только после вставки HTML в DOM. Пример с динамическим рендерингом:

router.on('/about', () => {
    fetch('/about.html')
        .then(res => res.text())
        .then(html => {
            const container = document.getElementById('about');
            container.innerHTML = html;
            animatePage('about');
        });
});

Особенности:

  • Анимация всегда должна запускаться после того, как элемент доступен в DOM.
  • Навигация через Navigo при динамическом контенте требует синхронизации с асинхронной загрузкой.

Комбинирование с CSS-анимациями элементов внутри страницы

Для сложных интерфейсов возможно добавлять анимацию не только контейнера страницы, но и отдельных элементов:

.page.active .fade-in {
    opacity: 0;
    transform: translateY(20px);
    animation: fadeInUp 0.5s forwards 0.2s;
}

@keyframes fadeInUp {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
function animateElements(pageId) {
    const page = document.getElementById(pageId);
    const elements = page.querySelectorAll('.fade-in');
    elements.forEach(el => el.style.animation = 'fadeInUp 0.5s forwards');
}

Особенности:

  • Использование animation-delay позволяет последовательно проявлять элементы.
  • Комбинирование с глобальной анимацией страницы создаёт более динамичный и привлекательный интерфейс.

Вывод

Комбинирование Navigo с CSS-анимациями позволяет создавать современный SPA-опыт без использования тяжёлых фреймворков. Основные принципы: управлять классами страниц через маршруты, использовать transition и animation, синхронизировать показ и скрытие элементов через события transitionend, и обеспечивать корректный запуск анимаций при динамическом контенте. Такая структура остаётся лёгкой, масштабируемой и полностью управляемой через CSS и JavaScript.