Квиз для подбора программы тренировок
Цель, уровень, сколько раз в неделю и ограничения по здоровью. На выходе — программа с расписанием на неделю и запись к тренеру.
<section class="vbkpt">
<div class="vbkpt-wrap">
<div class="vbkpt-box">
<div class="vbkpt-top">
<h2 class="vbkpt-h2">Подберём программу тренировок</h2>
<span class="vbkpt-step" id="vbkpt-step"></span>
</div>
<div class="vbkpt-bar"><i id="vbkpt-fill"></i></div>
<div class="vbkpt-stage" id="vbkpt-stage" aria-live="polite"></div>
<button type="button" class="vbkpt-back" id="vbkpt-back" hidden>Назад</button>
</div>
</div>
</section>
<style>
.vbkpt, .vbkpt *, .vbkpt *::before, .vbkpt *::after { box-sizing: border-box; }
.vbkpt {
--acc: #d6f24b; --acc-dark: #c2df33; --bg: #131518; --panel: #1c1f24; --ink: #f2f4f6; --muted: #939ba5; --line: #2a2e35;
--f: var(--t-text-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif);
--fh: var(--t-headline-font, var(--f));
background: var(--bg); color: var(--ink); font-family: var(--f); padding: clamp(36px, 5vw, 80px) 20px;
}
.vbkpt-wrap { max-width: 980px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbkpt-box { background: var(--panel); border: 1px solid var(--line); border-radius: 26px; padding: clamp(24px, 3vw, 44px); }
.vbkpt-top { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 14px; }
.vbkpt-h2 { font-family: var(--fh); font-size: clamp(23px, 3vw, 34px); line-height: 1.1; font-weight: 700; letter-spacing: -.025em;
text-transform: uppercase; margin: 0; }
.vbkpt-step { font-size: 13px; color: var(--muted); white-space: nowrap; }
.vbkpt-bar { height: 4px; border-radius: 4px; background: #2a2e35; overflow: hidden; margin-bottom: 28px; }
.vbkpt-bar i { display: block; height: 100%; width: 0; border-radius: 4px; background: var(--acc); transition: width .35s cubic-bezier(.22,1,.36,1); }
.vbkpt-q { font-family: var(--fh); font-size: clamp(18px, 1.9vw, 23px); line-height: 1.3; font-weight: 600; margin: 0 0 18px; }
.vbkpt-opts { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }
.vbkpt-opt { border: 1.5px solid var(--line); margin: 0; -webkit-appearance: none; appearance: none; font: inherit; cursor: pointer;
background: transparent !important; color: var(--ink) !important; border-radius: 14px; padding: 16px 18px; text-align: left; transition: .18s ease; }
.vbkpt-opt:hover { border-color: var(--acc); background: rgba(214,242,75,.06) !important; }
.vbkpt-opt b { display: block; font-size: 15.5px; font-weight: 600; }
.vbkpt-opt i { display: block; font-style: normal; font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.vbkpt-skip { display: inline-block; margin-top: 12px; border: 0; padding: 0; background: none !important; cursor: pointer;
font: inherit; font-size: 13.5px; color: var(--muted) !important; text-decoration: underline; }
.vbkpt-back { border: 0; margin: 20px 0 0; padding: 0; -webkit-appearance: none; appearance: none; background: none !important; cursor: pointer;
font: inherit; font-size: 14px; color: var(--muted) !important; text-decoration: underline; }
.vbkpt-back:hover { color: var(--acc) !important; }
.vbkpt-res__ttl { font-family: var(--fh); font-size: clamp(21px, 2.4vw, 29px); font-weight: 700; margin: 0 0 8px; }
.vbkpt-res__txt { font-size: 15.5px; line-height: 1.6; color: var(--muted); margin: 0 0 22px; max-width: 46em; }
.vbkpt-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; margin-bottom: 24px; }
.vbkpt-day { background: rgba(255,255,255,.04); border-radius: 12px; padding: 12px 8px; text-align: center; min-height: 92px; }
.vbkpt-day.is-rest { background: transparent; box-shadow: inset 0 0 0 1px var(--line); }
.vbkpt-day b { display: block; font-size: 11px; color: var(--muted); margin-bottom: 8px; text-transform: uppercase; letter-spacing: .04em; }
.vbkpt-day span { display: block; font-size: 12.5px; line-height: 1.35; font-weight: 600; }
.vbkpt-day.is-rest span { color: var(--muted); font-weight: 400; }
.vbkpt-day.is-on { background: var(--acc); }
.vbkpt-day.is-on b, .vbkpt-day.is-on span { color: #131518; }
.vbkpt-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.vbkpt-inp { width: 100%; height: 54px; padding: 0 16px; font: inherit; font-size: 16px; -webkit-appearance: none; appearance: none;
border: 1px solid var(--line); border-radius: 10px; background: rgba(255,255,255,.05); color: var(--ink); }
.vbkpt-inp::placeholder { color: #6f7883; }
.vbkpt-inp:focus { outline: 2px solid var(--acc); outline-offset: -2px; }
.vbkpt-consent { display: flex; align-items: flex-start; gap: 9px; margin: 12px 0 14px; cursor: pointer; font-size: 12px; line-height: 1.45; color: var(--muted); }
.vbkpt-consent input { position: absolute; opacity: 0; width: 0; height: 0; }
.vbkpt-consent__box { flex: 0 0 18px; width: 18px; height: 18px; margin-top: 1px; border: 1.5px solid #3b414a; border-radius: 5px; position: relative; }
.vbkpt-consent input:checked + .vbkpt-consent__box { background: var(--acc); border-color: var(--acc); }
.vbkpt-consent input:checked + .vbkpt-consent__box::after { content: ''; position: absolute; left: 5px; top: 1px; width: 5px; height: 10px; border: solid #131518; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.vbkpt-consent a, .vbkpt-consent a:link, .vbkpt-consent a:visited, .vbkpt-consent a:hover, .vbkpt-consent a:active, .vbkpt-consent a:focus { color: var(--ink) !important; text-decoration: underline !important; }
.vbkpt-submit { width: 100%; min-height: 56px; border: 0; margin: 0; -webkit-appearance: none; appearance: none; font: inherit; font-size: 16px;
font-weight: 700; text-transform: uppercase; letter-spacing: .04em; cursor: pointer; border-radius: 10px;
background: var(--acc) !important; color: #131518 !important; transition: background .2s ease; }
.vbkpt-submit:hover { background: var(--acc-dark) !important; }
.vbkpt-done { text-align: center; padding: 36px 8px; }
.vbkpt-done b { display: block; font-family: var(--fh); font-size: 21px; margin-bottom: 8px; }
.vbkpt-done span { font-size: 14px; color: var(--muted); }
@media (max-width: 700px) { .vbkpt-week { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 520px) { .vbkpt-opts { grid-template-columns: minmax(0, 1fr); } .vbkpt-two { grid-template-columns: minmax(0, 1fr); } .vbkpt-week { grid-template-columns: repeat(2, minmax(0, 1fr)); } .vbkpt-top { flex-direction: column; gap: 6px; } }
@media (prefers-reduced-motion: reduce) { .vbkpt * { transition: none !important; } }
</style>
<script>
(function () {
/* ── ВОПРОСЫ ── */
var STEPS = [
{ q: 'Какая цель ближе?', name: 'Цель', key: 'goal', opts: [
{ t: 'Сбросить вес', s: 'жир, а не мышцы', v: 'cut' },
{ t: 'Набрать массу', s: 'силовые в приоритете', v: 'mass' },
{ t: 'Привести в тонус', s: 'общая форма', v: 'tone' },
{ t: 'Выносливость', s: 'бег, дыхалка', v: 'endur' }
]},
{ q: 'Какой у вас опыт?', name: 'Уровень', key: 'level', opts: [
{ t: 'Первый раз в зале', s: 'нужна техника', v: 'start' },
{ t: 'Занимался раньше', s: 'был перерыв', v: 'back' },
{ t: 'Тренируюсь регулярно', s: 'от года', v: 'pro' }
]},
{ q: 'Сколько раз в неделю готовы приходить?', name: 'Частота', key: 'freq', opts: [
{ t: '2 раза', s: 'плотный график', v: 2 },
{ t: '3 раза', s: 'оптимально', v: 3 },
{ t: '4 раза и больше', s: 'есть время', v: 4 }
]},
{ q: 'Есть ограничения по здоровью?', name: 'Ограничения', key: 'limits', optional: true, opts: [
{ t: 'Спина', s: 'грыжи, протрузии', v: 'back' },
{ t: 'Колени', s: 'мениск, связки', v: 'knee' },
{ t: 'Давление', s: 'гипертония', v: 'press' },
{ t: 'Ограничений нет', s: '', v: 'none' }
]}
];
/* ── ПРОГРАММЫ: week — семь дней, пустая строка = отдых ── */
var PROGRAMS = {
cut: { ttl: 'Жиросжигание: круговые плюс кардио',
txt: 'Круговые тренировки держат пульс в жиросжигающей зоне, а силовая часть сохраняет мышцы — без неё вес уходит вместе с ними. Кардио ставим после силовой, не до.',
week: ['Круговая, всё тело', '', 'Кардио 40 мин', '', 'Круговая, всё тело', 'Прогулка или бассейн', ''] },
mass: { ttl: 'Набор массы: сплит по группам мышц',
txt: 'Работа в диапазоне 6–10 повторений с прогрессией веса. Между тренировками одной группы — минимум 48 часов на восстановление, иначе роста не будет.',
week: ['Грудь и трицепс', 'Спина и бицепс', '', 'Ноги и пресс', 'Плечи и руки', '', ''] },
tone: { ttl: 'Тонус: фулбоди три раза в неделю',
txt: 'Всё тело за тренировку, умеренные веса, много базовых движений. Самый устойчивый формат для тех, кто хочет форму, а не рекорды.',
week: ['Фулбоди A', '', 'Фулбоди B', '', 'Фулбоди A', 'Растяжка', ''] },
endur: { ttl: 'Выносливость: интервалы и длинные сессии',
txt: 'Чередуем интервальные тренировки и длинные равномерные. Силовая нужна для суставов и экономичности бега — она в программе одна, но обязательна.',
week: ['Интервалы 6×400 м', '', 'Силовая для бегуна', 'Лёгкий бег 30 мин', '', 'Длинная сессия', 'Растяжка'] }
};
var DAYS = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
var roots = document.querySelectorAll('.vbkpt');
for (var i = 0; i < roots.length; i++) init(roots[i]);
function init(root) {
if (root.__vb) return; root.__vb = 1;
var idx = 0, ans = {};
var stage = root.querySelector('#vbkpt-stage'), fill = root.querySelector('#vbkpt-fill');
var step = root.querySelector('#vbkpt-step'), back = root.querySelector('#vbkpt-back');
function drawStep() {
var s = STEPS[idx];
step.textContent = 'Шаг ' + (idx + 1) + ' из ' + STEPS.length;
fill.style.width = (idx / STEPS.length * 100) + '%';
back.hidden = idx === 0;
stage.innerHTML = '<h3 class="vbkpt-q">' + s.q + '<\/h3><div class="vbkpt-opts">' +
s.opts.map(function (o, i) {
return '<button type="button" class="vbkpt-opt" data-i="' + i + '"><b>' + o.t + '<\/b>' + (o.s ? '<i>' + o.s + '<\/i>' : '') + '<\/button>';
}).join('') + '<\/div>' +
(s.optional ? '<button type="button" class="vbkpt-skip">Пропустить вопрос<\/button>' : '');
stage.querySelectorAll('.vbkpt-opt').forEach(function (b) {
b.addEventListener('click', function () { ans[s.key] = s.opts[+b.dataset.i]; next(); });
});
var skip = stage.querySelector('.vbkpt-skip');
if (skip) skip.addEventListener('click', next);
}
function next() {
idx++;
if (idx < STEPS.length) drawStep(); else drawResult();
}
function drawResult() {
step.textContent = 'Программа готова';
fill.style.width = '100%';
back.hidden = false;
var goal = (ans.goal || {}).v || 'tone';
var p = PROGRAMS[goal];
var freq = (ans.freq || {}).v || 3;
/* если готовы приходить реже — убираем лишние тренировочные дни с конца */
var week = p.week.slice();
var trainDays = week.filter(function (d) { return d; }).length;
for (var i = week.length - 1; i >= 0 && trainDays > freq; i--) {
if (week[i]) { week[i] = ''; trainDays--; }
}
var summary = Object.keys(ans).map(function (k) {
var s = STEPS.filter(function (x) { return x.key === k; })[0];
return s ? s.name + ': ' + ans[k].t : '';
}).filter(Boolean).join('; ');
stage.innerHTML =
'<h3 class="vbkpt-res__ttl">' + p.ttl + '<\/h3>' +
'<p class="vbkpt-res__txt">' + p.txt + '<\/p>' +
'<div class="vbkpt-week">' + week.map(function (d, i) {
return '<div class="vbkpt-day ' + (d ? 'is-on' : 'is-rest') + '"><b>' + DAYS[i] + '<\/b><span>' + (d || 'отдых') + '<\/span><\/div>';
}).join('') + '<\/div>' +
'<form class="vbkpt-form t-form js-form-proccess" role="form" action="#" method="POST" ' +
'data-vibeblock-form="true" data-formactiontype="2" data-error-popup="y" data-success-popup="y" ' +
'data-success-callback="vbkptSuccess" data-inputbox=".vbkpt-inp, .vbkpt-consent-inp" novalidate>' +
'<input type="hidden" name="formservices[]" value="HASH_EMAIL" class="js-formaction-services">' +
'<input type="hidden" name="form_source" value="Квиз — подбор тренировок">' +
'<input type="hidden" name="Programma" value="' + p.ttl + '. ' + summary + '">' +
'<div class="vbkpt-two">' +
'<input type="text" name="Name" class="vbkpt-inp js-tilda-rule" data-tilda-req="1" data-tilda-rule="name" placeholder="Имя">' +
'<input type="tel" name="Phone" class="vbkpt-inp js-tilda-rule js-tilda-mask" data-tilda-req="1" data-tilda-rule="phone" ' +
'data-tilda-mask="+7 (999) 999-99-99" inputmode="tel" placeholder="+7 (___) ___-__-__"><\/div>' +
'<label class="vbkpt-consent"><input type="checkbox" name="Privacy" value="Da" class="vbkpt-consent-inp js-tilda-rule" data-tilda-req="1">' +
'<span class="vbkpt-consent__box"><\/span><span>Согласен с <a href="/policy" target="_blank" rel="noopener">политикой конфиденциальности<\/a><\/span><\/label>' +
'<button type="submit" class="vbkpt-submit t-submit">Забрать программу и записаться<\/button><\/form>';
var form = root.querySelector('.vbkpt-form');
if (form && !form.__b) {
form.__b = 1;
form.addEventListener('submit', function (e) {
e.preventDefault();
var btn = form.querySelector('button[type="submit"], .t-submit');
if (btn && typeof window.t_forms__initBtnClick === 'function') {
try { window.t_forms__initBtnClick({ target: btn, srcElement: btn, preventDefault: function () {} }); } catch (_) {}
}
});
}
}
back.addEventListener('click', function () { if (idx > 0) { idx--; drawStep(); } });
if (!window.vbkptSuccess) {
window.vbkptSuccess = function (f) {
try { f.innerHTML = '<div class="vbkpt-done"><b>Программа у тренера<\/b><span>Пришлём план в мессенджер и предложим время бесплатной вводной тренировки.<\/span><\/div>'; } catch (e) {}
};
}
drawStep();
}
})();
</script> Вставляется целиком в блок T123 «HTML-код». Внутри уже есть стили и скрипт, подключать ничего не нужно. В форме замените HASH_EMAIL на хеш приёмника из Tilda → Site Settings → Forms.
Как вставить блок в Tilda
- Скопируйте кодКнопка «Скопировать код» выше кладёт всё содержимое в буфер обмена.
- Добавьте блок T123В редакторе страницы: «Библиотека блоков» → «Другое» → T123 «HTML-код».
- Вставьте и сохранитеНажмите «Контент», вставьте код в поле, сохраните и обновите страницу.
- ОпубликуйтеВ превью скрипты Tilda работают не всегда — проверяйте на опубликованной странице.
Подробная инструкция с граблями — как вставить вайб-блок в Tilda.
Что менять под себя
| Где в коде | За что отвечает |
|---|---|
массив STEPS | вопросы и варианты |
объект PROGRAMS | программы и расписание на неделю |
--acc | цвет прогресса и дней недели |
formservices[] | приёмники заявок Tilda |
Квиз «Подбор программы тренировок»: зачем он нужен
Расписание на неделю в результате — то, что отличает этот квиз от обычной анкеты. Человек получает готовый план: понедельник — ноги, среда — верх, пятница — кардио. Ценность видна сразу, и контакт оставляют охотнее.
Вопрос об ограничениях по здоровью стоит намеренно последним и не обязателен. Он повышает качество заявки для тренера, но не отпугивает на первом шаге.
Вопросы по этому блоку
-
В объекте PROGRAMS у каждой программы лежит массив из семи элементов — по одному на день недели. Пустая строка означает день отдыха.
-
Да, включая выбранную программу — тренеру не нужно переспрашивать цель и уровень.
-
Да. Код на этой странице копируется целиком, без регистрации и подписки. Указывать авторство не нужно, использовать можно в коммерческих проектах.
-
Нет. Все классы внутри имеют собственный префикс vbkpt, поэтому не пересекаются ни со стилями Tilda, ни с другими блоками. Скрипт привязан к своему элементу и запускается один раз, даже если блок вставлен дважды.
-
Раскладка перестраивается под узкие экраны, размеры заданы через clamp, поля ввода имеют шрифт 16 пикселей — iOS не будет зумить страницу при фокусе. Отдельной мобильной версии подключать не нужно.
Другие квизы
Ещё блоки для фитнеса и спорта
Собрать сайт целиком, а не по блокам
Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса.