Горизонтальный скролл в 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 килобайт ради одного эффекта.