Блок «Сеты и цены» для доставки еды
Карточки сетов с составом, весом и ценой. У каждого — счётчик количества, а внизу блока считается сумма заказа.
<section class="vbstd">
<div class="vbstd-wrap">
<div class="vbstd-head">
<h2 class="vbstd-h2">Сеты на компанию</h2>
<p class="vbstd-lead">Собраны так, чтобы хватило и не осталось лишнего. Состав указан полностью — без «и другие роллы».</p>
</div>
<div class="vbstd-grid" id="vbstd-grid"></div>
<div class="vbstd-bar" id="vbstd-bar" hidden>
<div class="vbstd-bar__in">
<div class="vbstd-bar__txt"><b id="vbstd-count"></b><span id="vbstd-list"></span></div>
<div class="vbstd-bar__sum"><b id="vbstd-sum"></b><a class="vbstd-order" id="vbstd-order" href="#zakaz">Оформить заказ</a></div>
</div>
</div>
</div>
</section>
<style>
.vbstd, .vbstd *, .vbstd *::before, .vbstd *::after { box-sizing: border-box; }
.vbstd {
--acc: #8a5a2b; --acc-dark: #6f4720; --ink: #24201b; --muted: #6d645a; --line: #e5ddd1; --soft: #faf6ef; --old: #b7453a;
--f: var(--t-text-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif);
--fh: var(--t-headline-font, var(--f));
background: #fff; color: var(--ink); font-family: var(--f); padding: clamp(36px, 5vw, 80px) 20px;
}
.vbstd-wrap { max-width: 1240px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbstd-head { max-width: 42em; margin-bottom: clamp(24px, 3vw, 40px); }
.vbstd-h2 { font-family: var(--fh); font-size: clamp(26px, 3.4vw, 42px); line-height: 1.1; font-weight: 700; letter-spacing: -.025em; margin: 0 0 12px; }
.vbstd-lead { font-size: 16px; line-height: 1.6; color: var(--muted); margin: 0; }
.vbstd-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.vbstd-card { display: flex; flex-direction: column; background: var(--soft); border-radius: 22px; overflow: hidden; }
.vbstd-card svg { display: block; width: 100%; height: auto; }
.vbstd-body { display: flex; flex-direction: column; flex: 1; padding: 18px 22px 22px; }
.vbstd-name { font-family: var(--fh); font-size: 19px; font-weight: 700; margin: 0 0 4px; }
.vbstd-w { font-size: 12.5px; color: var(--muted); margin: 0 0 12px; }
.vbstd-comp { list-style: none; margin: 0 0 16px; padding: 0; flex: 1; display: grid; gap: 6px; }
.vbstd-comp li { display: flex; align-items: flex-start; gap: 8px; font-size: 13.5px; line-height: 1.45; color: var(--muted); }
.vbstd-comp li::before { content: ''; flex: 0 0 5px; width: 5px; height: 5px; margin-top: 7px; border-radius: 50%; background: var(--acc); }
.vbstd-price { display: flex; align-items: baseline; gap: 10px; margin-bottom: 14px; }
.vbstd-price b { font-family: var(--fh); font-size: 23px; font-weight: 700; }
.vbstd-price s { font-size: 14px; color: var(--old); }
.vbstd-count { display: flex; align-items: center; gap: 10px; }
.vbstd-count button { width: 40px; height: 40px; border: 1.5px solid var(--line); margin: 0; -webkit-appearance: none; appearance: none;
font: inherit; font-size: 20px; line-height: 1; cursor: pointer; border-radius: 50%; background: #fff !important; color: var(--ink) !important; transition: .18s ease; }
.vbstd-count button:hover { border-color: var(--acc); color: var(--acc) !important; }
.vbstd-count b { min-width: 28px; text-align: center; font-family: var(--fh); font-size: 17px; font-weight: 700; }
.vbstd-add, .vbstd-add:link, .vbstd-add:visited, .vbstd-add:active, .vbstd-add:focus { display: inline-flex; align-items: center; justify-content: center;
flex: 1; min-height: 44px; border-radius: 999px; font-size: 14.5px; font-weight: 600;
background: var(--acc); color: #fff !important; text-decoration: none !important; border: 0; cursor: pointer; transition: background .2s ease; }
.vbstd-add:hover { background: var(--acc-dark); color: #fff !important; }
.vbstd-bar { position: sticky; bottom: 12px; margin-top: 20px; z-index: 5; }
.vbstd-bar[hidden] { display: none; }
.vbstd-bar__in { display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
background: var(--ink); color: #fff; border-radius: 18px; padding: 16px 22px; }
.vbstd-bar__txt b { display: block; font-family: var(--fh); font-size: 16px; }
.vbstd-bar__txt span { display: block; font-size: 12.5px; color: #b1a89c; margin-top: 3px; }
.vbstd-bar__sum { display: flex; align-items: center; gap: 16px; }
.vbstd-bar__sum b { font-family: var(--fh); font-size: 22px; font-weight: 700; white-space: nowrap; }
.vbstd-order, .vbstd-order:link, .vbstd-order:visited, .vbstd-order:active, .vbstd-order:focus { display: inline-flex; align-items: center; justify-content: center;
min-height: 46px; padding: 0 24px; border-radius: 999px; font-size: 15px; font-weight: 600; white-space: nowrap;
background: #fff; color: var(--ink) !important; text-decoration: none !important; }
.vbstd-order:hover { background: #f0e9df; color: var(--ink) !important; }
@media (max-width: 560px) { .vbstd-bar__in { flex-direction: column; align-items: stretch; } .vbstd-bar__sum { justify-content: space-between; } }
@media (prefers-reduced-motion: reduce) { .vbstd * { transition: none !important; } }
</style>
<script>
(function () {
var COUNTER = true; /* false — обычная витрина без счётчиков */
var ORDER_HREF = '#zakaz'; /* куда ведёт кнопка оформления */
/* ── СЕТЫ: old — старая цена, пусто — зачёркивания не будет ── */
var SETS = [
{ name: 'Дружеский', w: '1 250 г · 48 шт.', price: 3290, old: 3990, c1: '#f3e6d4', c2: '#c9a877',
comp: ['Филадельфия с лососем, 8 шт.', 'Калифорния с крабом, 8 шт.', 'Запечённый с угрём, 8 шт.', 'Ролл с креветкой темпура, 8 шт.', 'Овощной ролл, 8 шт.', 'Гункан с икрой, 8 шт.'] },
{ name: 'Семейный', w: '1 800 г · 64 шт.', price: 4590, old: 5490, c1: '#e9e0d0', c2: '#b79b6f',
comp: ['Филадельфия классик, 16 шт.', 'Чизу с лососем, 8 шт.', 'Запечённый с курицей, 16 шт.', 'Хот-ролл с крабом, 8 шт.', 'Сладкий ролл, 8 шт.', 'Кальмар в панировке, 8 шт.'] },
{ name: 'Лёгкий', w: '760 г · 32 шт.', price: 1990, old: '', c1: '#e3ead9', c2: '#8fa477',
comp: ['Овощной ролл, 8 шт.', 'Ролл с авокадо, 8 шт.', 'Ролл с тунцом, 8 шт.', 'Салат чука, 200 г'] },
{ name: 'Мясной', w: '1 400 г · 6 позиций', price: 3890, old: 4290, c1: '#ecdcd4', c2: '#b07f68',
comp: ['Стейк из свиной шеи, 300 г', 'Куриные крылья барбекю, 400 г', 'Колбаски гриль, 300 г', 'Печёный картофель, 250 г', 'Соус на выбор, 2 шт.', 'Овощи гриль, 150 г'] }
];
var roots = document.querySelectorAll('.vbstd');
for (var i = 0; i < roots.length; i++) init(roots[i]);
function init(root) {
if (root.__vb) return; root.__vb = 1;
var grid = root.querySelector('#vbstd-grid'), bar = root.querySelector('#vbstd-bar');
var cart = {};
function fmt(n) { return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ' '); }
function word(n) { var m = n % 100, k = n % 10; return m > 10 && m < 20 ? 'сетов' : k === 1 ? 'сет' : k > 1 && k < 5 ? 'сета' : 'сетов'; }
/* SVG-заглушка блюда: замените на <img src="..." alt="Название сета"> */
function plate(c1, c2) {
return '<svg viewBox="0 0 300 170" role="img" aria-label="Изображение сета" focusable="false">' +
'<rect width="300" height="170" fill="' + c1 + '"/>' +
'<circle cx="150" cy="90" r="62" fill="#fff" opacity=".6"/>' +
'<circle cx="150" cy="90" r="46" fill="' + c2 + '" opacity=".35"/>' +
'<g fill="' + c2 + '">' +
'<circle cx="126" cy="74" r="13"/><circle cx="158" cy="68" r="13"/><circle cx="176" cy="94" r="13"/>' +
'<circle cx="150" cy="112" r="13"/><circle cx="120" cy="104" r="13"/><\/g>' +
'<g fill="#fff" opacity=".85">' +
'<circle cx="126" cy="74" r="5"/><circle cx="158" cy="68" r="5"/><circle cx="176" cy="94" r="5"/>' +
'<circle cx="150" cy="112" r="5"/><circle cx="120" cy="104" r="5"/><\/g><\/svg>';
}
grid.innerHTML = SETS.map(function (s, i) {
var ctrl = COUNTER
? '<div class="vbstd-count"><button type="button" data-i="' + i + '" data-d="-1" aria-label="Убрать один">−<\/button>' +
'<b data-n="' + i + '">0<\/b>' +
'<button type="button" data-i="' + i + '" data-d="1" aria-label="Добавить один">+<\/button>' +
'<button type="button" class="vbstd-add" data-i="' + i + '" data-d="1">В заказ<\/button><\/div>'
: '<div class="vbstd-count"><a class="vbstd-add" href="' + ORDER_HREF + '">Заказать<\/a><\/div>';
return '<article class="vbstd-card">' + plate(s.c1, s.c2) +
'<div class="vbstd-body"><h3 class="vbstd-name">' + s.name + '<\/h3>' +
'<p class="vbstd-w">' + s.w + '<\/p>' +
'<ul class="vbstd-comp">' + s.comp.map(function (c) { return '<li>' + c + '<\/li>'; }).join('') + '<\/ul>' +
'<div class="vbstd-price"><b>' + fmt(s.price) + ' ₽<\/b>' + (s.old ? '<s>' + fmt(s.old) + ' ₽<\/s>' : '') + '<\/div>' +
ctrl + '<\/div><\/article>';
}).join('');
if (!COUNTER) return;
grid.querySelectorAll('button[data-i]').forEach(function (b) {
b.addEventListener('click', function () {
var i = +b.dataset.i, d = +b.dataset.d;
cart[i] = Math.max(0, (cart[i] || 0) + d);
grid.querySelector('b[data-n="' + i + '"]').textContent = cart[i];
renderBar();
});
});
function renderBar() {
var n = 0, sum = 0, names = [];
Object.keys(cart).forEach(function (i) {
if (!cart[i]) return;
n += cart[i]; sum += cart[i] * SETS[i].price;
names.push(SETS[i].name + (cart[i] > 1 ? ' ×' + cart[i] : ''));
});
bar.hidden = n === 0;
if (!n) return;
root.querySelector('#vbstd-count').textContent = n + ' ' + word(n) + ' в заказе';
root.querySelector('#vbstd-list').textContent = names.join(', ');
root.querySelector('#vbstd-sum').textContent = fmt(sum) + ' ₽';
root.querySelector('#vbstd-order').setAttribute('href', ORDER_HREF);
}
}
})();
</script> Вставляется целиком в блок T123 «HTML-код». Внутри уже есть стили и скрипт, подключать ничего не нужно.
Как вставить блок в Tilda
- Скопируйте кодКнопка «Скопировать код» выше кладёт всё содержимое в буфер обмена.
- Добавьте блок T123В редакторе страницы: «Библиотека блоков» → «Другое» → T123 «HTML-код».
- Вставьте и сохранитеНажмите «Контент», вставьте код в поле, сохраните и обновите страницу.
- ОпубликуйтеВ превью скрипты Tilda работают не всегда — проверяйте на опубликованной странице.
Подробная инструкция с граблями — как вставить вайб-блок в Tilda.
Что менять под себя
| Где в коде | За что отвечает |
|---|---|
массив SETS | название, состав, вес, цена, старая цена |
ORDER_HREF | куда ведёт кнопка оформления |
--acc | цвет цены и кнопок |
Сеты и цены доставки: зачем он нужен
Доставке нужен не прайс, а витрина с быстрым добавлением. Счётчик прямо на карточке убирает лишний шаг: человек набирает заказ, не уходя со страницы, и видит сумму внизу.
Старая цена показывается только там, где она реально задана — блок не рисует фальшивых зачёркиваний. Состав сета вынесен списком, потому что именно по нему сравнивают предложения.
Вопросы по этому блоку
-
Нет, это витрина с подсчётом суммы. Состав заказа передаётся в форму или в ссылку оформления строкой. Полноценную корзину на Tilda лучше делать штатным каталогом.
-
В скрипте есть флаг COUNTER — поставьте false, и карточки станут обычными витринными, с одной кнопкой заказа.
-
Да. Код на этой странице копируется целиком, без регистрации и подписки. Указывать авторство не нужно, использовать можно в коммерческих проектах.
-
Нет. Все классы внутри имеют собственный префикс vbstd, поэтому не пересекаются ни со стилями Tilda, ни с другими блоками. Скрипт привязан к своему элементу и запускается один раз, даже если блок вставлен дважды.
-
Раскладка перестраивается под узкие экраны, размеры заданы через clamp, поля ввода имеют шрифт 16 пикселей — iOS не будет зумить страницу при фокусе. Отдельной мобильной версии подключать не нужно.
Другие блоки тарифов
Ещё блоки для ресторанов и доставки
Собрать сайт целиком
Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса.