Плавный переход между страницами на Тильде убирает белую вспышку между разделами сайта: браузер выгружает старую страницу, грузит новую с нуля, и в момент между этим экран моргает, особенно на мобильном интернете или когда на странице тяжёлые шрифты и Zero Block галереи. Я ставлю такую анимацию почти в каждом проекте на Тильде: занимает 15-20 минут работы, не требует сторонних библиотек и работает через нативный CSS-переход на opacity, который запускается JS-скриптом при клике по ссылке и при загрузке новой страницы.
По теме статьи
Готовое решение
Автоматическая конвертация валюты на Tilda
Цены товаров в нужной валюте по актуальному курсу ЦБ — автоматически и в реальном времени.
от6 000 ₽
Кастомный скрипт
Когда стандартных блоков не хватает
Доработка сайтов на Тильде: скрипты для корзины, промокоды, зоны доставки, интеграции с CRM и Telegram. Простой скрипт от 3 000
от3 000 ₽
Зачем плавный переход между страницами нужен на Тильде
Тильда не SPA-конструктор: каждая страница сайта это отдельный HTML-документ, который браузер загружает заново, со своими скриптами, шрифтами и Zero Block блоками. Из-за этого при переходе между разделами почти всегда виден белый (или чёрный, если тема тёмная) кадр между старой и новой страницей. Он длится от 100 до 500 мс в зависимости от скорости соединения и веса страницы, но глазом читается как рывок.
На практике это особенно заметно на интернет-магазинах с карточками товаров: подгружаются кастомные шрифты, инициализируются скрипты фильтров, и переход между каталогом и карточкой товара выглядит дёрганым. У одного клиента с магазином на Тильде, около 400 товаров и карточки на Zero Block, после добавления fade-перехода в 250 мс жалобы на «сайт дёргается» в тикетах поддержки пропали полностью, хотя скорость загрузки не изменилась ни на миллисекунду. Изменилось только восприятие.
Второй практический повод, это брендинг. На лендингах и мультилендингах, где важна целостность впечатления (курсы, агентства недвижимости, шоурумы), рваный переход между страницами визуально спорит с аккуратной вёрсткой. Фейд-переход стоит недорого по времени разработки и заметно поднимает субъективное качество сайта в глазах заказчика.
Как работает анимация: фейд при уходе и при загрузке
Схема простая и без хитрой магии:
- при загрузке страницы тег html получает opacity: 0 и плавно поднимается до 1 через CSS-transition;
- при клике по внутренней ссылке скрипт перехватывает переход через preventDefault, запускает fade-out (opacity: 0) и только через 200-300 мс после начала анимации меняет window.location.href;
- исключения: ссылки с target=“_blank”, якоря на этой же странице (начинаются с #), mailto:, tel: и внешние домены не трогаем, там переход и так открывается иначе, а фейд может всё сломать.
Длительность анимации я обычно беру 250-350 мс с easing cubic-bezier(0.4, 0, 0.2, 1), это стандартная кривая ускорения из material design, она не ощущается как зависание интерфейса. Меньше 200 мс браузер не успевает загрузить новую страницу, и вспышка всё равно проскакивает между fade-out и появлением нового html. Больше 400 мс уже читается как тормознутость, особенно на мобильном, где и так есть задержка сети.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Рабочий скрипт для плавного перехода на Тильде
Вот вариант, который я использую на реальных проектах. Работает без jQuery, без зависимостей, весит меньше 1 КБ.
(function () {
var DURATION = 300;
document.documentElement.style.transition = 'opacity ' + DURATION + 'ms ease';
document.documentElement.style.opacity = '0';
window.addEventListener('load', function () {
requestAnimationFrame(function () {
document.documentElement.style.opacity = '1';
});
});
document.addEventListener('click', function (e) {
var link = e.target.closest('a[href]');
if (!link) return;
if (link.target === '_blank') return;
if (link.hasAttribute('download')) return;
var href = link.getAttribute('href');
if (!href) return;
if (href.indexOf('#') === 0) return;
if (href.indexOf('mailto:') === 0) return;
if (href.indexOf('tel:') === 0) return;
if (link.host !== window.location.host) return;
e.preventDefault();
document.documentElement.style.opacity = '0';
setTimeout(function () {
window.location.href = href;
}, DURATION);
});
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
document.documentElement.style.opacity = '1';
}
});
})();
closest(‘a[href]’) ловит клик по любой ссылке, даже если внутри неё лежит текст в span или иконка. Проверки на target, download, mailto/tel и внешний host защищают от ситуаций, когда фейд запускается там, где переход всё равно произойдёт иначе: открытие в новой вкладке, скачивание файла, звонок. Слушатель pageshow с проверкой e.persisted нужен из-за bfcache, кеша браузера для кнопки «назад»: без этой проверки страница при возврате назад может остаться с opacity: 0, потому что скрипт не отработает заново.
Куда вставлять код в Тильде
Для вставки на весь сайт разом иду в Настройки сайта, затем Ещё, затем Вставка кода, и в поле «Внутри тега head, на всех страницах». Это доступно на платных тарифах Tilda с поддержкой вставки кода на весь сайт, а не только на отдельную страницу. Скрипт из примера выше вставляю целиком, обёрнутым в тег script, прямо в head, это важно, чтобы opacity: 0 применился до того, как браузер отрисует контент, иначе будет короткая вспышка исходного вида страницы перед анимацией.
Если доступа к общесайтовому коду нет (например, тариф ограничивает вставку только для конкретной страницы), добавляю код через настройки каждой страницы отдельно: Настройки страницы, Ещё, Вставка кода, поле «В head страницы». Дольше по времени на сайте из 10-15 страниц, зато работает без апгрейда тарифа.
После вставки обязательно проверяю страницу в режиме инкогнито и с отключённым кешем в devtools. Тильда кеширует опубликованные страницы на CDN, и без принудительной публикации через кнопку «Опубликовать» изменения в head можно не увидеть ещё 5-10 минут.
Типичные проблемы и как их лечу
Белая вспышка перед анимацией. Возникает, если скрипт вставлен в конец body или подключён с атрибутами async/defer, браузер успевает отрисовать страницу с opacity: 1 до того, как JS обнулит её. Лечится вставкой скрипта строго в head без async и defer, синхронным блоком в самом начале документа.
Анимация проигрывается дважды при переходе назад. Классическая история с bfcache: браузер восстанавливает страницу из памяти без перезагрузки, событие load не срабатывает повторно, а opacity могла остаться нулевой после fade-out. Решение, слушатель pageshow с проверкой event.persisted, как в скрипте выше.
Конфликт с попапами и Zero Block квизами. Если анимацию вешать на body, а не на html, некоторые блоки с position: fixed (плавающие кнопки, виджеты обратной связи) наследуют transition и тоже начинают мигать при открытии и закрытии. Поэтому в моём варианте анимация висит на document.documentElement, то есть на теге html, а не на body, это меньше конфликтует с абсолютным позиционированием внутри Zero Block.
Задержка перед переходом ощущается как лаг на медленном интернете. Тут технически неверно винить именно анимацию: 300 мс задержки перед сменой location.href добавляются поверх времени загрузки следующей страницы. На медленном мобильном соединении итоговая задержка ощущается заметнее. Для мобильного трафика иногда снижаю DURATION до 200 мс через проверку ширины экрана, чтобы не удлинять и без того небыстрый переход.
Когда самописного фейда недостаточно
Разница между плавным переходом через fade и настоящим SPA-переходом, как в Barba.js или Swup, где новая страница подгружается через fetch без полной перезагрузки, в том, что fetch-подход не перезагружает шрифты, скрипты и стили заново, переход выглядит ещё бесшовнее. Но для Тильды это скорее лишний риск, чем выигрыш: каждая страница тянет собственный набор инлайн-скриптов (галереи, аналитика, счётчики), рассчитанных на полную перезагрузку DOM. При подгрузке без полной перезагрузки часть этих скриптов не переинициализируется и ломает галереи, формы или каталог, приходится вручную дёргать функции переинициализации Тильды на каждый переход. Это уже не 20 минут работы, а полноценная интеграция с тестированием на каждой странице сайта.
Таблица ниже, как я обычно выбираю подход под задачу:
| Способ | Сложность | Когда беру |
|---|---|---|
| CSS-transition без JS | низкая | только фейд у отдельных блоков на странице, не между страницами |
| JS-фейд (скрипт из статьи) | средняя | для большинства сайтов на Тильде: лендинги, каталоги, мультилендинги |
| Barba.js / Swup с fetch-подгрузкой | высокая | редко, только если на сайте нет тяжёлых Zero Block скриптов и есть время на полное тестирование каждой страницы |
Если нужна более сложная доработка под конкретный сайт, например разные анимации для разных разделов каталога, синхронизация фейда с прелоадером или интеграция с внешним меню, такие задачи я беру как кастомную доработку сайтов на Тильде. Оцениваю обычно после короткого просмотра структуры сайта и списка проблемных страниц.
Частые вопросы
Замедлит ли анимация переходов индексацию сайта в Тильде?
Нет. Скрипт не блокирует загрузку HTML и не скрывает контент от поискового робота, opacity: 0 применяется к уже отрисованному DOM, а не мешает парсингу разметки. Googlebot рендерит JS и спокойно доходит до содержимого страницы даже с задержкой в 300 мс перед переходом, это на порядки меньше таймаутов, которые робот закладывает на выполнение скриптов.
Работает ли такой скрипт на мобильной версии Тильды?
Да, код одинаковый для десктопной и мобильной вёрстки, переход между страницами происходит на уровне браузера, а не адаптива. Исключение, AMP-версии страниц Тильды, если они включены в настройках: AMP запрещает произвольный JS, и фейд там не сработает, для страниц с анимацией перехода AMP лучше отключить.
Можно ли сделать разную анимацию для разных страниц сайта?
Можно. Добавляю проверку по классу или id тега body в начале скрипта и меняю длительность или тип transition, например translateY вместе с opacity, для конкретных разделов. Для интернет-магазина обычно делаю более короткий и незаметный фейд на страницах каталога и чуть более выразительный, с лёгким сдвигом по вертикали, на страницах услуг.
После установки скрипта страница осталась белой, картинки не появляются, в чём дело?
В большинстве случаев причина в том, что opacity: 1 в конце анимации не устанавливается, потому что событие load не срабатывает, например из-за медленно грузящегося внешнего шрифта или скрипта, который блокирует load. Проверяю консоль на ошибки JS, временно убираю из head сторонние виджеты (чаты, форму обратного звонка) по одному и смотрю, какой из них держит load. Второй частый случай, конфликт с уже установленным на сайте прелоадером Тильды, который тоже управляет opacity страницы: тогда два скрипта спорят за одно и то же CSS-свойство, и логику нужно объединить в одном месте.