Tilda · 8 мин чтения

Кастомное меню для Тильды с анимацией: разбор решения

Стандартный блок меню в Тильде - это T450 или T968 с десятком готовых пресетов, и когда дизайнер приносит макет с бургером, который разворачивается на весь экран с задержкой на каждый пункт, штатных настроек уже не хватает. Кастомное меню для Тильды с анимацией собирается через Zero Block или блок T123 с кастомным кодом, и в этой статье я разберу, из каких частей оно состоит, что не сработает через инспектор и на что закладывать бюджет.

Зачем кастомное меню, если в Тильде есть готовые блоки

Штатные меню Тильды закрывают процентов 80 задач: горизонтальная навигация, простой бургер на мобилке, липкий хедер с базовым fade. Но как только в макете появляется полноэкранный оверлей с анимацией пунктов по очереди, мегаменю с превью-картинками при наведении или смена цвета логотипа при скролле через секцию с тёмным фоном - все эти вещи через настройки блока не собрать, максимум получится имитация с задержками через стандартные анимации Тильды, которая на мобильных дёргается.

Я в таких случаях беру Zero Block как контейнер под разметку меню и навешиваю логику через кастомный JS-код в футере страницы или в T123. Если задача разовая и несложная - правки под конкретный макет, без интеграций - можно опереться на уже готовые решения, я собираю рабочие сниппеты для Тильды в библиотеке готовых скриптов, там есть база под бургер-меню с анимацией, которую проще адаптировать, чем писать с нуля.

Когда точно нужен кастом, а не настройки блока

На практике кастомное меню оправдано в трёх случаях: когда меню должно вести себя по-разному в зависимости от секции под хедером (тёмная/светлая тема), когда пункты анимируются не как единый блок, а по очереди (stagger-эффект), и когда бургер должен превращаться в крестик плавной трансформацией линий, а не простой заменой иконки.

Разметка меню: Zero Block вместо стандартного блока

Базовая структура - фиксированный хедер с логотипом, кнопкой-бургером и скрытой панелью навигации. Я обычно верстаю так, чтобы панель с пунктами меню существовала в DOM всегда, а её видимость и позиция управлялись классом на body или на самой панели - это упрощает анимацию и не требует пересоздавать элементы через JS при каждом открытии.

<header class="custom-header">
  <a href="/" class="logo">Логотип</a>
  <button class="burger" aria-label="Открыть меню">
    <span></span>
    <span></span>
    <span></span>
  </button>
  <nav class="menu-panel">
    <a href="#" class="menu-item">Главная</a>
    <a href="#" class="menu-item">Услуги</a>
    <a href="#" class="menu-item">Контакты</a>
  </nav>
</header>

Важный момент - этот блок вставляется в Zero Block через html-код, а не через встроенный редактор Тильды, потому что редактор добавляет обёртки div с автогенерируемыми классами, которые потом ломают селекторы в CSS при пересборке страницы.

CSS-анимация: transform вместо height

Самая частая ошибка, которую я вижу в чужих реализациях - анимация через изменение height или display у панели меню. Это работает, но дёргано, потому что height не анимируется плавно на auto, а браузер пересчитывает layout на каждый кадр. Я анимирую через transform и opacity - они обрабатываются на уровне композитора, без перерасчёта верстки, и на слабых мобильных телефонах разница в плавности заметна сразу.

.menu-panel {
  position: fixed;
  inset: 0;
  transform: translateX(100%);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

body.menu-open .menu-panel {
  transform: translateX(0);
}

.menu-item {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.3s ease, transform 0.3s ease;
}

body.menu-open .menu-item:nth-child(1) { transition-delay: 0.1s; opacity: 1; transform: none; }
body.menu-open .menu-item:nth-child(2) { transition-delay: 0.16s; opacity: 1; transform: none; }
body.menu-open .menu-item:nth-child(3) { transition-delay: 0.22s; opacity: 1; transform: none; }

Stagger-эффект, когда пункты появляются по очереди, я делаю именно через nth-child с разными transition-delay - никакого JS-таймера не нужно, всё решается каскадом CSS-правил, привязанных к одному классу на body.

Бургер, который трансформируется в крестик

Три span внутри кнопки поворачиваются и сдвигаются так, чтобы верхняя и нижняя линии сложились в крестик, а средняя исчезла:

.burger span {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

body.menu-open .burger span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
body.menu-open .burger span:nth-child(2) {
  opacity: 0;
}
body.menu-open .burger span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

JS-логика: открытие, закрытие, блокировка скролла

Сама логика открытия - это переключение одного класса на body, дальше всё отрабатывает CSS. Но нужно закрыть меню по клику на пункт, по клику вне панели и по нажатию Escape, а на мобильных ещё и заблокировать скролл фонового контента, пока меню открыто, иначе на iOS страница будет прокручиваться под панелью.

document.addEventListener('DOMContentLoaded', function () {
  var burger = document.querySelector('.burger');
  var body = document.body;

  function toggleMenu() {
    var isOpen = body.classList.toggle('menu-open');
    body.style.overflow = isOpen ? 'hidden' : '';
  }

  burger.addEventListener('click', toggleMenu);

  document.querySelectorAll('.menu-item').forEach(function (item) {
    item.addEventListener('click', function () {
      body.classList.remove('menu-open');
      body.style.overflow = '';
    });
  });

  document.addEventListener('keydown', function (e) {
    if (e.key === 'Escape' && body.classList.contains('menu-open')) {
      toggleMenu();
    }
  });
});

Этот код я вешаю в T123 с типом “до /body” - важно проверить, что скрипт не конфликтует с нативным зумом Тильды и с антифликер-скриптом, который используется для A/B‑тестов, иначе меню может “мигать” при первой отрисовке страницы.

Sticky-хедер и смена стиля при скролле

Вторая частая задача - хедер, который меняет фон или цвет логотипа после прокрутки, а не просто прилипает сверху. Стандартная настройка “фиксировать при скролле” в Тильде переключает только позиционирование, без учёта пройденного расстояния или секции под хедером. Я обычно навешиваю IntersectionObserver на первый экран и переключаю класс у хедера, когда он выходит из зоны видимости:

var hero = document.querySelector('.t-rec:first-of-type');
var header = document.querySelector('.custom-header');

if (hero && header) {
  var observer = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      header.classList.toggle('header--solid', !entry.isIntersecting);
    });
  }, { threshold: 0 });

  observer.observe(hero);
}

IntersectionObserver дешевле по производительности, чем обработчик scroll с пересчётом offsetTop на каждый кадр - это особенно заметно на длинных лендингах с десятком секций T968, где обычный scroll-listener начинает подтормаживать на мобильных.

Вариант меню Плавность анимации Гибкость под макет Где собирается
Штатный блок Тильды (T450, T968) Средняя, есть рывки на мобильных Низкая, ограничена пресетами Настройки блока
Кастом через Zero Block + CSS transform Высокая Высокая, под любой макет Zero Block + T123
Кастом с GSAP Максимальная, сложные тайминги Максимальная, включая SVG-морфинг Zero Block + T123 + подключение GSAP

GSAP я подключаю, когда в макете есть что-то сложнее stagger-появления пунктов: морфинг иконки бургера через SVG-path, параллакс фона панели меню или синхронизация анимации меню с анимацией самого лого. Для простых кейсов библиотека избыточна - 40 строк CSS решают задачу без лишней зависимости, которая грузится с CDN и добавляет вес странице.

Частые ошибки при внедрении кастомного меню в Тильде

Перечислю то, с чем реально сталкивался при доработке чужих проектов:

  • Скрипт меню вставлен в один T123 на конкретной странице, а не в настройках сайта - при добавлении новой страницы бургер на ней просто не работает
  • Z‑index панели меню ниже, чем у попапов Тильды (форм захвата, виджетов обратного звонка) - меню открывается, но перекрывается другими элементами
  • Анимация завязана на классы, которые Тильда переименовывает при пересборке блока в редакторе - после правок в визуальном редакторе меню перестаёт анимироваться
  • Не протестирован Safari на iOS - там position: fixed внутри панели ведёт себя иначе при открытой клавиатуре или при скролле с bounce-эффектом
  • Забыли про доступность: фокус не переводится на первый пункт меню при открытии, и пользователь с клавиатуры не может добраться до навигации

Последний пункт часто игнорируют, а зря - если на сайт заходят через скринридер или клавиатурную навигацию, отсутствие управления фокусом в кастомном меню превращает его в тупик для части посетителей.

Сколько это стоит и сколько занимает по времени

Точечная правка существующего меню - поменять таймингы анимации, добавить stagger-эффект на пункты, поправить баг с overflow на мобильных - я оцениваю от 3 000 ₽, это займёт от пары часов до дня, в зависимости от того, насколько запутан существующий код на странице.

Полноценное кастомное меню с нуля - с адаптивом под все брейкпоинты, sticky-логикой, сменой темы по секциям и тестированием в разных браузерах - я беру от 15 000 ₽. На рынке за похожую задачу студии и фрилансеры просят и 10 000, и 50 000 ₽ в зависимости от сложности макета и опыта исполнителя, но у меня фикс складывается из готовой базы скриптов, которую я адаптирую под конкретный проект, а не собираю с нуля каждый раз.

Если меню нужно завязать на что-то ещё - например, на статус авторизации пользователя через личный кабинет на Тильде или на данные из CRM - это уже комплексная интеграция, и там счёт идёт от 40 000 ₽, потому что добавляется работа с API и обработкой ошибок на бэкенде.

Когда стандартных блоков не хватает

Кастомный скрипт

от 3 000 ₽

Подробнее →

Частые вопросы

Можно ли сделать анимированное меню без Zero Block, через обычные блоки Тильды?

Частично можно - стандартные блоки поддерживают простые fade и slide-эффекты через настройки анимации Тильды, но точный контроль над таймингами, задержками по каждому пункту и трансформацией иконки бургера доступен только через кастомный код в Zero Block или T123.

Ломается ли кастомное меню при обновлениях Тильды?

Сам движок Тильды меню не трогает, но если верстка лежит внутри стандартного блока, а не в Zero Block, редактор может переименовать служебные классы при повторном сохранении страницы - поэтому я всегда выношу структуру меню в Zero Block, где классы фиксированные и их никто не переписывает автоматически.

Нужен ли GSAP для простой анимации бургер-меню?

Нет, для базового сценария - открытие панели, stagger пунктов, трансформация бургера в крестик - хватает CSS transition и transform. GSAP оправдан, когда в анимации участвует SVG-морфинг, синхронизация нескольких элементов по таймлайну или физика (инерция, эластичность).

Как проверить, что меню не тормозит на слабых телефонах?

Я смотрю на панель производительности в Chrome DevTools с троттлингом CPU в 4-6 раз и включённым режимом Mobile - если анимация идёт через transform и opacity, просадок обычно нет даже на симуляции слабого устройства. Если анимация завязана на height, width или top/left, просадки будут видны сразу на этом же тесте.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Самозанятый Калинкин Н. А. · работаю с физлицами и юрлицами

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно