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

Кнопка на Тильде: свои стили, состояния и обработка клика

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

Зачем переопределять стандартную кнопку в Tilda

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

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

Второй частый повод - интеграция. Кнопка должна не просто вести по ссылке, а запускать сценарий: открывать кастомный попап с расчётом стоимости, дергать вебхук перед переходом, менять текст в зависимости от выбора пользователя на странице. Это уже не про дизайн, а про поведение, и решается через JavaScript поверх верстки, которую отдаёт Tilda. На одном из проектов кнопка «Рассчитать доставку» на карточке товара должна была сначала дернуть свой обработчик и только потом, если расчёт прошёл, открывать попап с формой заказа - без своего кода такую цепочку в конструкторе не собрать.

Где искать класс кнопки и как его зацепить

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

У кнопки в Tilda почти всегда есть базовый класс t-btn, плюс служебный класс конкретного блока вроде t756__btn, а у кнопки отправки формы это t-submit. Писать CSS сразу по этим классам рискованно: при смене скина блока или обновлении верстки блока Tilda эти классы могут поменяться, и стиль слетит при следующей правке страницы, о которой вы можете даже не узнать.

Практичнее добавить кнопке собственный класс и вешать стили уже на него:

  • в блоке Zero Block у каждого элемента, включая кнопку, есть поле Class в настройках - туда вписывается произвольное имя, например my-btn-primary;
  • в обычных блоках такого поля у кнопки нет, но можно задать ID блоку в настройках блока и писать CSS через этот ID как через дополнительный селектор;
  • для HTML-блока T123 класс просто прописывается в разметке, которую вы сами вставляете.

Три способа закрывают разные ситуации, и выбор зависит от того, где физически стоит кнопка на странице.

Способ Где встречается Когда использовать
Поле Class в Zero Block Блоки на конструкторе Zero Block Нужен свой стиль конкретному элементу без правки чужой верстки
ID блока + CSS в head Стандартные блоки (T123, T450, T‑form и другие) Нужно перекрыть стиль внутри блока, у которого нет своего поля класса
Верстка в HTML-блоке T123 Полностью кастомная секция Кнопка не встроена в готовый блок, а верстается с нуля

CSS в любом из вариантов вставляется через настройки страницы: «Ещё» - «Вставить код в head» на уровне страницы или всего сайта, если стиль должен работать везде.

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

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

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

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

Свои стили кнопки через CSS

Когда класс на кнопке есть, стиль пишется как обычный CSS, только с чуть более высокой специфичностью, чем у исходных стилей блока, иначе Tilda-стили пересилят ваши:

.my-btn-primary {
 background: linear-gradient(135deg, #2f6feb, #1b4fb8);
 border-radius: 10px;
 padding: 14px 32px;
 font-weight: 600;
 transition: transform .15s ease, box-shadow .15s ease;
 box-shadow: 0 4px 14px rgba(27, 79, 184, .25);
}

.my-btn-primary:hover {
 transform: translateY(-2px);
 box-shadow: 0 8px 20px rgba(27, 79, 184, .35);
}

Форма и анимация без прыжков верстки

Анимацию завязываю на transform и box-shadow, а не на изменение padding или font-size по hover - от них соседние элементы блока дёргаются, потому что меняется реальный размер кнопки. Тень и сдвиг на пару пикселей визуально работают так же выразительно, но не ломают раскладку.

Отдельно учитываю, что на телефонах и планшетах события hover фактически нет - палец не «наводит», а сразу нажимает. Если весь эффект кнопки завязан только на hover, на мобильных он просто не увидится, поэтому важные визуальные подсказки дублирую через состояние active, которое срабатывает и на тач-устройствах тоже.

Состояния кнопки: hover, active, disabled, загрузка

У кнопки в Tilda обычно нет нативного атрибута disabled, потому что рендерится она как ссылка <a>, а не как <button> - исключение - кнопка отправки формы, она честный <button type="submit">. Поэтому состояние «недоступна» делаю через класс и pointer-events, а не через атрибут:

.my-btn-primary.is-disabled {
 opacity: .5;
 pointer-events: none;
 box-shadow: none;
}

.my-btn-primary.is-loading {
 position: relative;
 color: transparent;
}

.my-btn-primary.is-loading::after {
 content: "";
 position: absolute;
 left: 50%;
 top: 50%;
 width: 16px;
 height: 16px;
 margin: -8px 0 0 -8px;
 border: 2px solid #fff;
 border-top-color: transparent;
 border-radius: 50%;
 animation: btn-spin .6s linear infinite;
}

@keyframes btn-spin {
 to { transform: rotate(360deg); }
}

Дальше классы is-disabled и is-loading навешиваются и снимаются уже из JavaScript в момент клика и после ответа сервера. Такой подход одинаково работает и для кнопки-ссылки, и для кнопки формы, и не требует разного кода под разные типы блоков.

Обработка клика: свой JavaScript без слома виджета

Код, который трогает кнопку, запускаю не сразу в head, а после того как Tilda отрисовала блоки на странице. Для этого использую обёртку t_onReady, которую Tilda сама подключает на страницах сайта - она гарантирует, что скрипт отработает после инициализации блоков, а не до того, как кнопка появилась в DOM:

t_onReady(function () {
 var btn = document.querySelector('.my-btn-primary');
 if (!btn) return;

 btn.addEventListener('click', function (e) {
 if (btn.classList.contains('is-disabled')) {
 e.preventDefault();
 return;
 }

 btn.classList.add('is-loading');

 fetch('/api/lead', {
 method: 'POST',
 headers: { 'Content-Type': 'application/json' },
 body: JSON.stringify({ source: 'landing-btn' })
 }).finally(function () {
 btn.classList.remove('is-loading');
 });
 });
});

Если кнопка ставится через Zero Block, у неё в настройках есть отдельный тип действия «JS-событие»: вписываете произвольное имя события, и по клику Tilda не переходит по ссылке, а генерирует это событие в браузере. Ловится оно обычным addEventListener на document, без необходимости искать элемент кнопки руками и без риска, что при переносе блока на другую страницу селектор перестанет находить кнопку:

document.addEventListener('openCalcPopup', function () {
 document.querySelector('.calc-popup').classList.add('is-open');
});

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

Кнопка отправки формы: валидация перед сабмитом

С кнопкой формы отдельная история: перед тем как форма Tilda уйдёт на отправку, часто нужно проверить что-то своё - например, что выбран способ доставки или отмечен чекбокс с промокодом. Вешаю обработчик на сам submit-клик и в нужных случаях останавливаю его через preventDefault, до того как сработает штатная отправка формы:

t_onReady(function () {
 var submitBtn = document.querySelector('.t-submit');
 if (!submitBtn) return;

 submitBtn.addEventListener('click', function (e) {
 var delivery = document.querySelector('input[name="delivery"]:checked');
 if (!delivery) {
 e.preventDefault();
 e.stopImmediatePropagation();
 alert('Выберите способ доставки');
 }
 }, true);
});

Третий параметр true у addEventListener важен: он ставит обработчик на фазу перехвата, и он срабатывает раньше внутреннего обработчика Tilda, поэтому stopImmediatePropagation реально успевает остановить отправку. Без этого параметра обработчики выполнятся в обратном порядке, и своя проверка сработает уже после того, как форма ушла на сервер.

Для аналитики по кнопке отдельный код обычно не нужен, но полей «цель Яндекс.Метрики» и «событие Google Analytics» в настройках блока нет. Есть галочка «Отправлять данные о клике в систему аналитики»: после её включения ниже появляется адрес виртуальной страницы, просмотр которой и означает клик по кнопке. Этот адрес подставляется в цель Метрики типа «Посещение страниц» в поле «url:содержит». У кнопки в Zero Block то же самое делается через Settings и поле Click tracking со значением Send data to analytics. Свой JS для трекинга имеет смысл, только если нужно передать в аналитику что-то нестандартное, например сумму заказа или выбранный тариф.

Когда сценарий на кнопке или форме выходит за рамки CSS и десятка строк JS, например, кнопка должна проверять остаток товара на складе перед отправкой заказа или дергать CRM с разными полями в зависимости от выбора пользователя, обычно проще сразу отдать кастомную доработку кнопок и скриптов для Tilda в работу, чем собирать логику из чужих примеров с форумов. Простая правка стилей и состояний укладывается в разработку от 3 000 ₽, а сценарий с интеграцией стороннего сервиса или CRM обычно оценивается как комплексная доработка от 40 000 ₽.

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

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

Можно ли поменять вид кнопки без кода, только через панель Tilda

Да, цвет, размер шрифта, радиус скругления и отступы у большинства блоков меняются прямо в панели настроек блока. Код нужен, когда требуется эффект за пределами этих полей: градиент, своя анимация при наведении, состояние disabled или loading.

Почему свой CSS для кнопки не применяется на сайте

Обычно причина в специфичности селектора: собственный класс должен быть написан так, чтобы перебивать исходные стили блока, иначе побеждают классы самой Tilda. Вторая частая причина - код вставлен в head конкретной страницы, а кнопка находится на другой странице сайта, где этот код не подключен, либо сохранился старый файл в кэше браузера.

Как не дать пользователю кликнуть по кнопке дважды подряд

Добавляю класс вроде is-loading сразу в обработчике клика и снимаю его после ответа сервера, а сам клик по кнопке с этим классом блокирую через pointer-events: none в CSS или проверку класса в начале обработчика. Это защищает от повторной отправки формы или двойного вызова вебхука.

Как передать клик по кнопке в Яндекс.Метрику или Google Analytics

Отдельных полей для цели Метрики и события GA у блока нет. В настройках блока с кнопкой включается галочка «Отправлять данные о клике в систему аналитики», Тильда начинает отдавать виртуальную страницу клика, и на её адрес в Метрике создаётся цель типа «Посещение страниц» с условием «url:содержит». В Zero Block аналог этой галочки это поле Click tracking со значением Send data to analytics. Свой обработчик клика нужен только под нестандартный сценарий, который так не описывается.

Есть задача?

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

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

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