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

Горизонтальный скролл карточек в Zero Block: пошаговая настройка на Tilda

Горизонтальный скролл в Zero Block я делаю на голом CSS с парой строк JS - без подключения Swiper или других библиотек, которые тянут за собой лишние 40-60 килобайт кода на страницу. Ниже - рабочая связка разметки, стилей и скрипта, которую я использую в проектах на Tilda, когда нужна лента карточек с прокруткой в сторону вместо стандартной сетки.

Когда горизонтальный скролл карточек оправдан в Zero Block

Стандартная сетка Zero Block отлично работает для 3-4 карточек в ряд, но если у клиента 8-12 позиций каталога, отзывов или кейсов, вертикальная простыня превращает страницу в бесконечную портянку. Горизонтальная лента решает это компактно: пользователь видит 2-3 карточки целиком и понимает, что можно листать дальше.

На практике беру этот приём для:

  • каталога товаров или услуг, когда карточек больше 6 и они однотипные;
  • ленты отзывов или кейсов - заказчики любят такой формат за компактность;
  • подборки тарифов или пакетов на лендинге, чтобы не растягивать блок на весь экран;
  • галереи фото с описанием, где обычный слайдер Tilda не даёт нужной ширины карточки.

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

Разметка блока в Zero Block под скролл-ленту

Базовый принцип: контейнер с overflow-x: auto и карточки внутри с фиксированной шириной, которые не переносятся на новую строку. В Zero Block это делается через элемент «Код» (T123) или прямо в настройках блока, если у вас есть доступ к HTML/CSS/JS блока целиком.

Вставляю такую структуру внутрь блока:

<div class="jc_hscroll">
  <div class="jc_hscroll__track">
    <div class="jc_hscroll__card">
      <img src="card1.jpg" alt="">
      <h3>Название карточки</h3>
      <p>Короткое описание</p>
    </div>
    <div class="jc_hscroll__card">...</div>
    <div class="jc_hscroll__card">...</div>
  </div>
  <button class="jc_hscroll__btn jc_hscroll__btn--prev" aria-label="Назад"></button>
  <button class="jc_hscroll__btn jc_hscroll__btn--next" aria-label="Вперёд"></button>
</div>

Важный момент - префикс класса. Zero Block уже использует свои служебные классы (t123, t-name и так далее), и если назвать контейнер просто .card или .wrapper, велик шанс конфликта со стилями соседнего блока или самой Tilda. Я всегда беру короткий уникальный префикс вроде jc_ - по инициалам проекта или клиента.

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

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

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

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

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

CSS: превращаем flex-ряд карточек в скролл-ленту

Весь эффект держится на трёх свойствах: display: flex, overflow-x: auto и flex-shrink: 0 у карточек, чтобы они не сжимались под ширину контейнера.

.jc_hscroll {
  position: relative;
}

.jc_hscroll__track {
  display: flex;
  gap: 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 8px;
}

.jc_hscroll__track::-webkit-scrollbar {
  display: none;
}

.jc_hscroll__card {
  flex: 0 0 280px;
  scroll-snap-align: start;
  cursor: grab;
}

.jc_hscroll__card:active {
  cursor: grabbing;
}

.jc_hscroll__btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,0.6);
  cursor: pointer;
  z-index: 2;
}

.jc_hscroll__btn--prev { left: 8px; }
.jc_hscroll__btn--next { right: 8px; }

scroll-snap-type: x mandatory вместе с scroll-snap-align: start на карточках - та самая штука, из-за которой лента не останавливается посередине карточки, а всегда докручивается до начала следующей. На iOS Safari это работает без дополнительного JS, на старых Android-браузерах иногда чуть дёргается - если проект чувствителен к этому, стоит протестировать на реальных устройствах, а не только в DevTools.

Ширину карточки (flex: 0 0 280px) подбираю под макет: на десктопе это может быть 300-340px, на мобильном лучше пересчитать через медиазапрос под 78-82% ширины экрана, чтобы был виден край следующей карточки - это визуально подсказывает пользователю, что ленту можно листать дальше.

JS-доработки: колесо мыши, драг курсором, кнопки навигации

Чистый CSS даёт скролл по свайпу на мобильном и по горизонтальной прокрутке трекпадом, но на десктопе с обычной мышью пользователь крутит колесо вертикально и лента просто не реагирует. Добавляю обработчик, который перенаправляет вертикальный скролл в горизонтальный, пока курсор над блоком:

document.addEventListener('DOMContentLoaded', function () {
  var track = document.querySelector('.jc_hscroll__track');
  if (!track) return;

  track.addEventListener('wheel', function (e) {
    if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
      track.scrollLeft += e.deltaY;
      e.preventDefault();
    }
  }, { passive: false });

  var isDown = false, startX, scrollLeft;

  track.addEventListener('mousedown', function (e) {
    isDown = true;
    startX = e.pageX - track.offsetLeft;
    scrollLeft = track.scrollLeft;
  });
  track.addEventListener('mouseleave', function () { isDown = false; });
  track.addEventListener('mouseup', function () { isDown = false; });
  track.addEventListener('mousemove', function (e) {
    if (!isDown) return;
    e.preventDefault();
    var x = e.pageX - track.offsetLeft;
    track.scrollLeft = scrollLeft - (x - startX) * 1.5;
  });

  var prev = document.querySelector('.jc_hscroll__btn--prev');
  var next = document.querySelector('.jc_hscroll__btn--next');
  var card = track.querySelector('.jc_hscroll__card');
  var step = card ? card.offsetWidth + 20 : 300;

  if (prev) prev.addEventListener('click', function () {
    track.scrollBy({ left: -step, behavior: 'smooth' });
  });
  if (next) next.addEventListener('click', function () {
    track.scrollBy({ left: step, behavior: 'smooth' });
  });
});

В Zero Block этот скрипт вешаю через элемент «Код» с типом JS, размещённый в конце блока, или через глобальный T123-код на весь сайт, если лента используется на нескольких страницах. Второй вариант удобнее поддерживать: правишь один файл, а не копию скрипта в каждом блоке.

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

Скролл-снап и мобильные жесты в Zero Block

На телефоне лента и так работает через нативный тач-скролл, JS для драга там не нужен и даже вреден - обработчики mousedown/mousemove иногда конфликтуют с тач-событиями на гибридных устройствах (ноутбуки с сенсорным экраном, некоторые Android-планшеты). Проверяю через window.matchMedia('(pointer: coarse)') и вешаю драг-скролл только там, где основной ввод - мышь:

var isTouchDevice = window.matchMedia('(pointer: coarse)').matches;
if (!isTouchDevice) {
  // навешиваем mousedown/mousemove только тут
}

Ещё одна деталь - кнопки-стрелки на мобильном лучше скрывать через display: none в медиазапросе до 768px: на маленьком экране они закрывают часть карточки и дублируют то, что и так делает свайп пальцем.

Отдельно проверяю поведение ленты внутри Zero Block, если на блоке включена анимация появления (fade-in, parallax) - движок Tilda иногда применяет transform к родительскому контейнеру блока, и это ломает position: sticky у кнопок навигации. Если кнопки должны быть прибиты к краю блока, а не к краю экрана, ставлю им position: absolute относительно .jc_hscroll, а не fixed - так они не съезжают при скролле анимированного родителя.

Частые проблемы при настройке горизонтального скролла в Zero Block

За несколько лет работы с Tilda накопился список типовых грабель, на которые наступают при добавлении горизонтального скролла в Zero Block:

Проблема Причина Что делаю
Лента не скроллится вообще Карточки не имеют фиксированной ширины, flex сжимает их под контейнер Добавляю flex-shrink: 0 и явную ширину карточке
Скролл дёргается на iPhone Нет -webkit-overflow-scrolling: touch или конфликт с scroll-snap-type Проверяю поддержку на реальном устройстве, не в эмуляторе Chrome
Стрелки перекрывают текст карточки Абсолютное позиционирование без отступа контента Добавляю padding первой и последней карточке под ширину кнопки
Скролл работает в редакторе, но не на опубликованной странице Код вставлен в T123 без обёртки в DOMContentLoaded Всегда оборачиваю скрипт в обработчик готовности DOM
Конфликт классов с другим блоком на странице Слишком общее имя класса (.card, .container) Уникальный префикс на каждый проект

Отдельно скажу про производительность: если карточек больше 20-30 и в каждой тяжёлая картинка, лучше сразу подключить loading="lazy" на img - иначе браузер грузит все изображения ленты разом, даже те, что пользователь может не долистать никогда.

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

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

от 3 000 ₽

Подробнее →

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

Можно ли сделать горизонтальный скролл в Zero Block без кода?

Частично - Zero Block Slider-элемент даёт горизontальную прокрутку из коробки, но с ограниченным контролем над шириной карточек, отступами и поведением на десктопе. Для точной подгонки под макет всё равно приходится добавлять свой CSS поверх стандартного слайдера или собирать блок с нуля через код.

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

Чаще всего дело в порядке загрузки скрипта: код в T123 должен быть обёрнут в DOMContentLoaded или размещён после разметки блока, иначе на опубликованной странице скрипт пытается найти элементы, которых ещё нет в DOM. Также проверяю, не кэшируется ли старая версия кода в CDN Tilda - иногда помогает жёсткая перезагрузка страницы с очисткой кэша.

Как добавить индикатор прокрутки (точки) к горизонтальной ленте?

Считаю количество карточек, делю ширину трека на ширину видимой области и рисую нужное число точек через JS, обновляя активную точку по событию scroll с троттлингом (например, раз в 100 мс, чтобы не грузить браузер). Готового элемента под это в Zero Block нет, нужен свой скрипт.

Стоит ли использовать Swiper вместо самописного скролла в Zero Block

Если на сайте уже есть Swiper под другие слайдеры - да, разумнее переиспользовать библиотеку, чем плодить два похожих механизма. Если это единственный скролл-блок на странице, самописный вариант на 40-60 строк CSS и JS легче и быстрее загружается, чем подключение библиотеки на 30-40 килобайт ради одного эффекта.

Есть задача?

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

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

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

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