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

Тильда меню: свои состояния и подсветка раздела

Базовая настройка тильда меню занимает пару минут в визуальном редакторе: цвета, шрифты, отступы между пунктами, автоматический бургер на мобильном. Но как только нужен нестандартный hover, подсветка активного раздела на одностраничнике при скролле или отдельная логика для мобильной версии, стандартных переключателей в панели блока не хватает. Собираю такие доработки на разных проектах на Тильде, и ниже разложил приёмы, которыми пользуюсь сам.

Что настраивается в меню Тильды без единой строчки кода

Прежде чем тянуться за скриптом, стоит пройтись по настройкам самого блока меню. В большинстве шапок (T450 и похожие) можно задать отдельные цвета текста и фона для обычного состояния и для наведения, включить фиксацию шапки при прокрутке страницы, выбрать анимацию появления бургера на мобильном и подключить встроенный переключатель языков, если сайт мультиязычный. Для мультистраничных сайтов Тильда сама подсвечивает пункт меню, соответствующий текущей странице, это включается прямо в настройках блока.
Чего в этой панели нет, так это состояний, завязанных на прокрутку одной длинной страницы, и тонкой настройки поведения меню именно на мобильном брейкпоинте отдельно от десктопа. Здесь я обычно перехожу либо к возможностям Zero Block, либо к своему скрипту.

Свои состояния пунктов через Zero Block

Если шапка собрана в Zero Block, у элементов есть пошаговая анимация, а внутри неё триггерная: кнопка ADD в блоке Step by step animation в настройках элемента, выбор события, затем Add trigger и клик по элементу, который будет триггером. События всего два, наведение (on Hover) и клик (on Click), прокрутки до определённого блока среди них нет. Для меню это удобно, когда нужно, скажем, менять цвет пункта при разворачивании выпадающего списка или подсвечивать кнопку авторизации отдельно от остальных ссылок.
Ограничение Zero Block в том, что триггером служит элемент того же блока, а событий всего два: наведение и клик. Если логика сложнее, например состояние должно зависеть от данных с бэкенда (пользователь залогинен через личный кабинет, в корзине есть товары) или от внешнего сервиса, триггерной анимации уже не хватает, и приходится довешивать JS поверх готовой вёрстки меню.

Подсветка активного раздела при скролле

Для одностраничников с якорными пунктами меню (Главная, Услуги, Кейсы, Контакты на одной странице) готового переключателя, который сам подсвечивал бы пункт по мере прокрутки, в настройках блока нет, эта логика добавляется скриптом. Раньше делал это через обработчик scroll и сравнение координат, сейчас проще и легче по производительности через IntersectionObserver, он не гоняет пересчёт при каждом пикселе прокрутки, а срабатывает только когда секция реально пересекает область видимости.

Вот рабочий вариант для меню, где ссылки ведут на якоря вида #section-id, а секции на странице имеют такие же id:

document.addEventListener('DOMContentLoaded', function () {
  var menuLinks = document.querySelectorAll('a[href^="#"]');
  var sections = [];

  menuLinks.forEach(function (link) {
    var id = link.getAttribute('href').slice(1);
    var section = document.getElementById(id);
    if (section) sections.push({ id: id, link: link, el: section });
  });

  var observer = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      var match = sections.find(function (s) { return s.el === entry.target; });
      if (!match) return;
      if (entry.isIntersecting) {
        menuLinks.forEach(function (l) { l.classList.remove('menu-active'); });
        match.link.classList.add('menu-active');
      }
    });
  }, { rootMargin: '-40% 0px -50% 0px', threshold: 0 });

  sections.forEach(function (s) { observer.observe(s.el); });
});

Класс menu-active навешиваю в T123 (собственный CSS блока) или в настройках стилей сайта, там же, где обычно храню кастомные классы для Тильды:

.t-menu__link-item.menu-active {
  color: #2d6cdf;
  font-weight: 600;
}

rootMargin с отрицательными отступами сверху и снизу задаёт узкую полосу примерно посередине экрана, именно попадание секции в эту полосу считается «активной». Значения подбираю под конкретный макет, если секции короткие и их много, полосу сужаю, если секции высокие, могу расширить.

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

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

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

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

Мобильное меню: адаптация и бургер

На мобильном брейкпоинте Тильда автоматически сворачивает меню в бургер и открывает список пунктов на весь экран или выезжающей панелью, в зависимости от выбранного в настройках блока варианта анимации. Там же настраиваются цвет иконки, фон панели и её ширина.
Проблема обычно не в том, что бургер не работает, а в том, что кастомная подсветка активного раздела, которую я вписал через IntersectionObserver, на мобильном ведёт себя иначе: пункты меню скрыты в панели, и подсветка в закрытом виде не видна пользователю, но при следующем открытии меню класс должен уже стоять на правильном пункте. Проверяю это отдельно, добавляя в скрипт медиазапрос через window.matchMedia, чтобы на мобильном подсветка срабатывала мягче, без резких переходов, которые на маленьком экране выглядят дёргано.
Второй момент, специфичный для мобильной версии, это высота шапки. Если меню фиксированное и шапка выше, чем на десктопе (из-за перенесённого логотипа или увеличенного шрифта), якорные ссылки промахиваются мимо секции на высоту шапки. Компенсирую это через scroll-margin-top у секций, а не через ручной пересчёт координат в скрипте, это надёжнее при смене темы или пересборке блока.

Фиксация меню при скролле и что при этом проседает

Встроенный переключатель «показывать при прокрутке» в настройках блока меню включает sticky-поведение без единой строчки кода, и в большинстве случаев этого достаточно. Но при фиксированной шапке плюс кастомном скрипте подсветки и плюс тяжёлых анимациях в самом меню на слабых мобильных устройствах иногда заметны подтормаживания при быстрой прокрутке.
Первое, что проверяю в таком случае, это не забыл ли повесить observer.disconnect() при уходе со страницы (для одностраничников с SPA-переходами внутри Тильды это актуально) и не запускается ли скрипт подсветки повторно при каждой перерисовке блока конструктором. Второе, использую ли анимации через transform и opacity вместо изменения top или height, это меньше нагружает рендер на телефонах.
Если доработка меню тянет за собой более серьёзную логику, например завязку на статус пользователя или на данные из внешней CRM, такую задачу обычно оформляю как кастомный скрипт для Tilda, а не пытаюсь дотянуть всё через стандартные настройки блока.

Где вставлять код и типичные ошибки

Скрипт подсветки вставляю в настройках сайта, в разделе с дополнительным кодом, в поле «до закрывающего тега body», это гарантирует, что DOM уже отрисован к моменту выполнения. Вставка того же кода в head без обёртки в DOMContentLoaded регулярно приводит к тому, что скрипт не находит нужные элементы, потому что блоки меню и секции ещё не успели отрендериться.
Из ошибок, которые чаще всего вижу на чужих проектах при разборе: дублирование id у секций (Тильда не всегда ругается на это явно, а скрипт с getElementById молча берёт первый попавшийся элемент), забытые классы после ручного редактирования вёрстки блока в Zero Block, из-за чего CSS для активного состояния просто перестаёт совпадать с селектором, и скрипты, скопированные с других сайтов без замены названий классов под конкретную структуру блока меню на этой странице.
Простая правка меню, вроде добавления одного нового состояния или подсветки одного якоря, стоит от 3 000 ₽. Если доработка идёт в связке с другими интеграциями на сайте, оценку считаю уже под конкретную задачу.

Условия и возможности Тильды меняются, поэтому перед запуском я уточняю их у самого сервиса.

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

Можно ли добавить несколько состояний пункта меню без программиста?

Если шапка собрана в Zero Block, да: через пошаговую анимацию с триггером (Step by step animation, кнопка ADD, событие on Hover или on Click, затем Add trigger) элемент меняет вид по наведению или клику прямо в редакторе. Для более сложной логики, завязанной на прокрутку или внешние данные, этого уже не хватает.

Как подсветить пункт меню при скролле по одностраничнику?

Готового переключателя для этого в блоке меню нет, добавляю такое поведение скриптом на IntersectionObserver: он отслеживает, какая секция сейчас в области видимости, и навешивает класс активного состояния на соответствующую ссылку меню.

Почему подсветка работает на десктопе, но не видна на мобильном?

На мобильном меню обычно свёрнуто в бургер, и активный пункт визуально не виден, пока панель закрыта. Логика при этом продолжает работать в фоне и обновляет класс, так что при открытии панели пользователь увидит правильно подсвеченный пункт, если скрипт отработал корректно и без привязки только к десктопным координатам.

Куда вставлять JS-код для кастомизации меню в Тильде?

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

Есть задача?

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

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

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