Блок тарифов на лечение для сайта клиники
Разовый приём, годовая и семейная программа в одном ряду. Тумблер вверху переключает цены и один пункт состава между взрослым и детским приёмом, снизу меняется пояснение.
<section class="vbtnl">
<div class="vbtnl-wrap">
<div class="vbtnl-head">
<div class="vbtnl-head__txt">
<h2 class="vbtnl-h2">Как оплачивать наблюдение</h2>
<p class="vbtnl-lead">Три способа: прийти один раз с конкретной жалобой, взять программу на год или подключить к ней вторую половину семьи. Цены меняются при переключении на детский приём.</p>
</div>
<div class="vbtnl-switch" id="vbtnl-switch" role="group" aria-label="Кому подбираем программу"></div>
</div>
<div class="vbtnl-grid" id="vbtnl-grid"></div>
<p class="vbtnl-note" id="vbtnl-note"></p>
</div>
</section>
<style>
.vbtnl, .vbtnl *, .vbtnl *::before, .vbtnl *::after { box-sizing: border-box; }
.vbtnl {
--acc: #1c7f8c; --acc-dark: #166874; --ink: #1d2b2e; --muted: #5f7276; --line: #dfe8e9; --soft: #f2f7f7;
--f: var(--t-text-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif);
--fh: var(--t-headline-font, var(--f));
background: var(--soft); color: var(--ink); font-family: var(--f); padding: clamp(36px, 5vw, 80px) 20px;
}
.vbtnl-wrap { max-width: 1160px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbtnl-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 22px; margin-bottom: clamp(24px, 3vw, 38px); }
.vbtnl-head__txt { max-width: 44em; }
.vbtnl-h2 { font-family: var(--fh); font-size: clamp(26px, 3.4vw, 40px); line-height: 1.12; font-weight: 600; letter-spacing: -.02em; margin: 0 0 12px; }
.vbtnl-lead { font-size: 16px; line-height: 1.65; color: var(--muted); margin: 0; }
.vbtnl-switch { display: inline-flex; gap: 4px; padding: 4px; background: #fff; border: 1px solid var(--line); border-radius: 999px; }
.vbtnl-sw { border: 0; margin: 0; -webkit-appearance: none; appearance: none; font: inherit; font-size: 15px; cursor: pointer;
padding: 11px 22px; border-radius: 999px; background: none !important; color: var(--muted) !important; transition: .2s ease; white-space: nowrap; }
.vbtnl-sw:hover { color: var(--acc) !important; }
.vbtnl-sw[aria-pressed="true"] { background: var(--acc) !important; color: #fff !important; font-weight: 600; }
.vbtnl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(275px, 1fr)); gap: 18px; align-items: stretch; }
.vbtnl-card { position: relative; display: flex; flex-direction: column; background: #fff; border: 1px solid var(--line);
border-radius: 20px; padding: clamp(22px, 2.4vw, 30px); }
.vbtnl-card--hot { border-color: var(--acc); box-shadow: 0 0 0 1px var(--acc); }
.vbtnl-badge { position: absolute; top: -11px; left: clamp(22px, 2.4vw, 30px); background: var(--acc); color: #fff;
font-size: 11.5px; font-weight: 600; border-radius: 999px; padding: 5px 12px; }
.vbtnl-name { font-family: var(--fh); font-size: 19px; font-weight: 600; margin: 0 0 8px; }
.vbtnl-for { font-size: 13.5px; line-height: 1.55; color: var(--muted); margin: 0 0 20px; min-height: 3.4em; }
.vbtnl-price { min-height: 76px; margin-bottom: 14px; transition: opacity .2s ease; }
.vbtnl-price b { display: block; font-family: var(--fh); font-size: clamp(26px, 2.8vw, 34px); line-height: 1.1; font-weight: 600; letter-spacing: -.02em; }
.vbtnl-price span { display: block; font-size: 12.5px; line-height: 1.5; color: var(--muted); margin-top: 7px; }
.vbtnl-price.is-swap { opacity: 0; }
.vbtnl-term { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--acc); background: var(--soft);
border-radius: 999px; padding: 7px 13px; margin: 0 0 18px; align-self: flex-start; }
.vbtnl-inc { list-style: none; margin: 0 0 22px; padding: 18px 0 0; border-top: 1px solid var(--line); flex: 1; display: grid; gap: 10px; align-content: start; }
.vbtnl-inc li { position: relative; padding-left: 22px; font-size: 14px; line-height: 1.5; }
.vbtnl-inc li::before { content: ''; position: absolute; left: 0; top: 7px; width: 12px; height: 2px; border-radius: 2px; background: var(--acc); }
.vbtnl-inc li.vbtnl-inc--mode { color: var(--acc); }
.vbtnl-cta, .vbtnl-cta:link, .vbtnl-cta:visited, .vbtnl-cta:active, .vbtnl-cta:focus { display: flex; align-items: center; justify-content: center;
margin-top: auto; min-height: 54px; border-radius: 12px; font-size: 16px; font-weight: 600;
background: var(--soft); color: var(--ink) !important; text-decoration: none !important; transition: .18s ease; }
.vbtnl-cta:hover { background: #e3eeef; color: var(--ink) !important; }
.vbtnl-card--hot .vbtnl-cta { background: var(--acc); color: #fff !important; }
.vbtnl-card--hot .vbtnl-cta:hover { background: var(--acc-dark); color: #fff !important; }
.vbtnl-note { margin: clamp(20px, 2.4vw, 30px) 0 0; font-size: 14px; line-height: 1.6; color: var(--muted); max-width: 52em; }
@media (prefers-reduced-motion: reduce) { .vbtnl * { transition: none !important; } }
</style>
<script>
(function () {
var CTA_HREF = '#zapis';
/* ── РЕЖИМЫ: между ними переключает верхний тумблер ── */
var MODES = [
{ id: 'adult', label: 'Взрослым', note: 'Цены указаны для пациентов старше 18 лет. Приём ведёт терапевт, при необходимости подключает профильных врачей клиники без доплаты за консилиум.' },
{ id: 'kid', label: 'Детям', note: 'Детские программы рассчитаны на возраст от года до 17 лет. Приём ведёт педиатр, прививки по календарю входят в годовую и семейную программу.' }
];
/* ── ПАКЕТЫ: price, sub и extra задаются отдельно для взрослых и детей ── */
var PACKS = [
{ name: 'Разовый приём', forWho: 'Разобраться с одной жалобой и получить назначения на руки', term: 'приём 40 минут', popular: false,
price: { adult: '2 400 ₽', kid: '2 100 ₽' },
sub: { adult: 'за приём, повторный в течение 14 дней входит в цену', kid: 'за приём, осмотр перед садиком входит в цену' },
inc: ['Осмотр и разбор жалобы', 'Назначения в письменном виде', 'Расшифровка анализов на повторном приёме'],
extra: { adult: 'Направление к профильному врачу', kid: 'Справка для сада или школы' } },
{ name: 'Годовая программа', forWho: 'Наблюдаться весь год у одного врача и не считать каждый визит', term: '12 месяцев', popular: true,
price: { adult: '32 000 ₽', kid: '27 500 ₽' },
sub: { adult: 'за год или 2 900 ₽ в месяц при помесячной оплате', kid: 'за год или 2 500 ₽ в месяц при помесячной оплате' },
inc: ['Приёмы врача без ограничения по числу', 'Плановое обследование один раз в год', 'Анализы по программе наблюдения', 'Электронная карта с историей приёмов'],
extra: { adult: 'Три вызова врача на дом', kid: 'Прививки по национальному календарю' } },
{ name: 'Семейная программа', forWho: 'Подключить двоих и вести карты в одном месте', term: '12 месяцев на двоих', popular: false,
price: { adult: '58 000 ₽', kid: '49 000 ₽' },
sub: { adult: 'за двоих взрослых, третий участник добавляется за 24 000 ₽', kid: 'за двоих детей, третий участник добавляется за 20 000 ₽' },
inc: ['Всё, что входит в годовую программу', 'Общий кабинет с картами участников', 'Запись на смежное время одним звонком'],
extra: { adult: 'Ведёт один терапевт на семью', kid: 'Ведёт один педиатр на обоих детей' } }
];
var roots = document.querySelectorAll('.vbtnl');
for (var i = 0; i < roots.length; i++) init(roots[i]);
function init(root) {
if (root.__vb) return; root.__vb = 1;
var sw = root.querySelector('#vbtnl-switch'), grid = root.querySelector('#vbtnl-grid'), note = root.querySelector('#vbtnl-note');
var mode = MODES[0].id;
sw.innerHTML = MODES.map(function (m) {
return '<button type="button" class="vbtnl-sw" data-m="' + m.id + '" aria-pressed="' + (m.id === mode) + '">' + m.label + '<\/button>';
}).join('');
grid.innerHTML = PACKS.map(function (p) {
return '<article class="vbtnl-card' + (p.popular ? ' vbtnl-card--hot' : '') + '">' +
(p.popular ? '<span class="vbtnl-badge">Берут чаще всего<\/span>' : '') +
'<h3 class="vbtnl-name">' + p.name + '<\/h3>' +
'<p class="vbtnl-for">' + p.forWho + '<\/p>' +
'<div class="vbtnl-price"><b><\/b><span><\/span><\/div>' +
'<p class="vbtnl-term">Срок: ' + p.term + '<\/p>' +
'<ul class="vbtnl-inc">' + p.inc.map(function (x) { return '<li>' + x + '<\/li>'; }).join('') +
'<li class="vbtnl-inc--mode"><\/li><\/ul>' +
'<a class="vbtnl-cta" href="' + CTA_HREF + '">Записаться<\/a><\/article>';
}).join('');
var cards = root.querySelectorAll('.vbtnl-card');
function paint(animate) {
for (var i = 0; i < cards.length; i++) {
var p = PACKS[i], box = cards[i].querySelector('.vbtnl-price');
box.querySelector('b').textContent = p.price[mode];
box.querySelector('span').textContent = p.sub[mode];
cards[i].querySelector('.vbtnl-inc--mode').textContent = p.extra[mode];
if (animate) {
box.classList.add('is-swap');
(function (b) { setTimeout(function () { b.classList.remove('is-swap'); }, 30); })(box);
}
}
for (var k = 0; k < MODES.length; k++) if (MODES[k].id === mode) note.textContent = MODES[k].note;
}
var btns = sw.querySelectorAll('.vbtnl-sw');
for (var b = 0; b < btns.length; b++) {
btns[b].addEventListener('click', function () {
mode = this.getAttribute('data-m');
for (var j = 0; j < btns.length; j++) btns[j].setAttribute('aria-pressed', btns[j].getAttribute('data-m') === mode ? 'true' : 'false');
var boxes = root.querySelectorAll('.vbtnl-price');
for (var q = 0; q < boxes.length; q++) boxes[q].classList.add('is-swap');
setTimeout(function () { paint(true); }, 170);
});
}
paint(false);
}
})();
</script> Вставляется целиком в блок T123 «HTML-код». Внутри уже есть стили и скрипт, подключать ничего не нужно.
Как вставить блок в Tilda
- Скопируйте кодКнопка «Скопировать код» выше кладёт всё содержимое в буфер обмена.
- Добавьте блок T123В редакторе страницы: «Библиотека блоков» → «Другое» → T123 «HTML-код».
- Вставьте и сохранитеНажмите «Контент», вставьте код в поле, сохраните и обновите страницу.
- ОпубликуйтеВ превью скрипты Tilda работают не всегда — проверяйте на опубликованной странице.
Подробная инструкция с граблями — как вставить вайб-блок в Tilda.
Что менять под себя
| Где в коде | За что отвечает |
|---|---|
массив MODES в начале скрипта | названия режимов тумблера и пояснение под сеткой |
массив PACKS | названия пакетов, состав, срок и признак популярного |
поля price и sub у пакета | цена и подпись под ней отдельно для взрослых и детей |
поле extra у пакета | пункт списка, который меняется вместе с режимом |
переменная CTA_HREF | якорь или адрес, куда ведёт кнопка «Записаться» |
Тарифы на лечение: зачем он нужен
В клинике почти всегда два прайса: взрослый и детский. Держать их двумя блоками неудобно, а сводить в таблицу долго и неудобно для чтения с телефона. Тумблер решает это за один клик: карточки остаются на месте, меняются только цифры, пояснение к цене и один пункт списка. Посетитель сравнивает пакеты между собой и сразу видит цену для своего случая.
Пакеты собираются из массива, где цена, подпись под ценой и отличающийся пункт заданы отдельно для каждого режима. При переключении цена гаснет и появляется обратно, поэтому изменение заметно даже боковым зрением. Средний пакет помечен бейджем и рамкой акцентного цвета, это подсказывает выбор без давления. Кнопка ведёт ссылкой на запись, форма внутри блока не собирается.
Вопросы по этому блоку
-
Да, режимы задаются массивом MODES. Поменяйте подписи и ключи, а в полях price, sub и extra используйте те же ключи, что стоят в id режима.
-
Допишите объект в массив PACKS с обоими вариантами цены. Сетка на auto-fit сама поставит карточку в ряд, на узком экране пакеты идут один под другим.
-
Блок ведёт на запись ссылкой, чтобы не дублировать формы Tilda на странице. Поставьте в CTA_HREF якорь своей формы или ссылку на виджет записи.
-
Да. Код на этой странице копируется целиком, без регистрации и подписки. Указывать авторство не нужно, использовать можно в коммерческих проектах.
-
Нет. Все классы внутри имеют собственный префикс vbtnl, поэтому не пересекаются ни со стилями Tilda, ни с другими блоками. Скрипт привязан к своему элементу и запускается один раз, даже если блок вставлен дважды.
-
Раскладка перестраивается под узкие экраны, размеры заданы через clamp, поля ввода имеют шрифт 16 пикселей — iOS не будет зумить страницу при фокусе. Отдельной мобильной версии подключать не нужно.
Другие блоки тарифов
Ещё блоки для медицины и стоматологии
Собрать сайт целиком, а не по блокам
Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса.