Стандартный блок меню в Тильде - это 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, просадки будут видны сразу на этом же тесте.