Задать вопрос директору
Telegram
VK
Звонок

Квиз подбора дома для загородного отдыха

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

Живое демо — блок работает прямо здесь

Код блока

<section class="vbkpo">
  <div class="vbkpo-wrap">
    <div class="vbkpo-head">
      <h2 class="vbkpo-h2">Какой дом брать на эти выходные</h2>
      <p class="vbkpo-lead">Четыре вопроса про компанию, повод и срок. В ответе конкретный дом с ценой за сутки, вместимостью и списком того, что есть на участке.</p>
    </div>

    <div class="vbkpo-box">
      <ol class="vbkpo-steps" id="vbkpo-steps"></ol>
      <div class="vbkpo-stage" id="vbkpo-stage" aria-live="polite"></div>
      <div class="vbkpo-foot">
        <button type="button" class="vbkpo-back" id="vbkpo-back" hidden>Назад к вопросу</button>
        <span class="vbkpo-num" id="vbkpo-num"></span>
      </div>
    </div>
  </div>
</section>

<style>
.vbkpo, .vbkpo *, .vbkpo *::before, .vbkpo *::after { box-sizing: border-box; }
.vbkpo {
  --acc: #4f7d43; --acc-dark: #3f6636; --ink: #1e2a20; --muted: #61735f; --line: #dde5d5; --soft: #f3f7ee; --wood: #a9743e;
  --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;
}
.vbkpo-wrap { max-width: 900px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbkpo-head { max-width: 42em; margin-bottom: clamp(22px, 3vw, 34px); }
.vbkpo-h2 { font-family: var(--fh); font-size: clamp(25px, 3.2vw, 38px); line-height: 1.1; font-weight: 700; letter-spacing: -.022em; margin: 0 0 12px; }
.vbkpo-lead { font-size: 16px; line-height: 1.6; color: var(--muted); margin: 0; }

.vbkpo-box { background: #fff; border: 1px solid var(--line); border-radius: 26px; padding: clamp(20px, 3vw, 40px); }
.vbkpo-steps { list-style: none; margin: 0 0 26px; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.vbkpo-steps li { font-size: 11.5px; line-height: 1.3; color: #9aa899; padding-top: 10px; border-top: 3px solid var(--line); transition: color .25s ease, border-color .25s ease; }
.vbkpo-steps li.vbkpo-on { color: var(--acc); border-top-color: var(--acc); font-weight: 600; }
.vbkpo-steps li.vbkpo-done { color: var(--muted); border-top-color: #9dbb8f; }

.vbkpo-q { font-family: var(--fh); font-size: clamp(19px, 2.2vw, 26px); line-height: 1.25; font-weight: 700; margin: 0 0 6px; }
.vbkpo-hint { font-size: 14px; line-height: 1.55; color: var(--muted); margin: 0 0 18px; }
.vbkpo-opts { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 10px; }
.vbkpo-opt { display: flex; align-items: flex-start; gap: 13px; width: 100%; margin: 0; padding: 16px 18px; text-align: left; font: inherit;
  -webkit-appearance: none; appearance: none; cursor: pointer; border: 1.5px solid var(--line); border-radius: 16px;
  background: #fff !important; color: var(--ink) !important; transition: .18s ease; }
.vbkpo-opt:hover { border-color: var(--acc); background: var(--soft) !important; }
.vbkpo-opt svg { flex: 0 0 24px; width: 24px; height: 24px; color: var(--acc); margin-top: 1px; }
.vbkpo-opt b { display: block; font-size: 15.5px; line-height: 1.35; font-weight: 600; }
.vbkpo-opt i { display: block; font-style: normal; font-size: 12.5px; line-height: 1.45; color: var(--muted); margin-top: 4px; }

.vbkpo-foot { display: flex; align-items: center; gap: 16px; margin-top: 22px; }
.vbkpo-back { border: 0; margin: 0; padding: 0; -webkit-appearance: none; appearance: none; background: none !important; cursor: pointer;
  font: inherit; font-size: 13.5px; color: var(--muted) !important; text-decoration: underline; }
.vbkpo-back:hover { color: var(--acc) !important; }
.vbkpo-num { margin-left: auto; font-size: 13px; color: var(--muted); }

.vbkpo-res__tag { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--wood);
  background: #faf2e8; border-radius: 999px; padding: 7px 15px; margin-bottom: 14px; }
.vbkpo-res__ttl { font-family: var(--fh); font-size: clamp(22px, 2.7vw, 31px); line-height: 1.15; font-weight: 700; margin: 0 0 10px; }
.vbkpo-res__txt { font-size: 15.5px; line-height: 1.65; color: var(--muted); margin: 0 0 20px; max-width: 40em; }
.vbkpo-res__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(145px, 1fr)); gap: 10px; margin-bottom: 16px; }
.vbkpo-res__grid div { background: var(--soft); border-radius: 14px; padding: 15px 17px; }
.vbkpo-res__grid b { display: block; font-family: var(--fh); font-size: 19px; font-weight: 700; letter-spacing: -.01em; }
.vbkpo-res__grid span { display: block; font-size: 12px; line-height: 1.4; color: var(--muted); margin-top: 5px; }
.vbkpo-res__has { list-style: none; margin: 0 0 22px; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.vbkpo-res__has li { font-size: 12.5px; color: var(--muted); border: 1px solid var(--line); border-radius: 999px; padding: 6px 13px; }
.vbkpo-acts { display: flex; flex-wrap: wrap; gap: 10px; }
.vbkpo-cta, .vbkpo-cta:link, .vbkpo-cta:visited, .vbkpo-cta:active, .vbkpo-cta:focus { display: inline-flex; align-items: center;
  justify-content: center; min-height: 54px; padding: 0 28px; border-radius: 13px; font-size: 16px; font-weight: 600;
  background: var(--acc); color: #fff !important; text-decoration: none !important; }
.vbkpo-cta:hover { background: var(--acc-dark); color: #fff !important; }
.vbkpo-again { min-height: 54px; padding: 0 24px; border: 1.5px solid var(--line); margin: 0; -webkit-appearance: none; appearance: none;
  font: inherit; font-size: 16px; cursor: pointer; border-radius: 13px; background: #fff !important; color: var(--ink) !important; }
.vbkpo-again:hover { border-color: var(--acc); }

@media (max-width: 620px) { .vbkpo-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (prefers-reduced-motion: reduce) { .vbkpo * { transition: none !important; } }
</style>

<script>
(function () {
  /* ── ШАГИ: k - вместимость, p - очки домам ── */
  var STEPS = [
    { tab: 'Гости', q: 'Сколько человек приедет?', hint: 'Считаем всех, включая детей старше трёх лет', opts: [
      { t: 'Вдвоём', s: 'одна спальня, вид на лес', k: 2, ic: '<circle cx="9" cy="8" r="3.2"/><path d="M3 20c0-3.3 2.7-5.4 6-5.4s6 2.1 6 5.4M17 8h4M19 6v4"/>', p: { kupol: 3, kedr: 1 } },
      { t: 'Трое или четверо', s: 'семья или две пары', k: 4, ic: '<path d="M4 19V9l8-5 8 5v10M4 19h16M10 19v-5h4v5"/>', p: { kedr: 3, banya: 1 } },
      { t: 'От пяти до восьми', s: 'друзья или две семьи', k: 8, ic: '<path d="M12 3l8 6v11H4V9zM9 20v-6h6v6"/>', p: { sruba: 3, banya: 2 } },
      { t: 'Больше девяти', s: 'группа с ночёвкой', k: 12, ic: '<path d="M3 20h18M5 20V8l7-4 7 4v12M9 20v-5h6v5"/>', p: { prichal: 4 } }
    ]},
    { tab: 'Повод', q: 'По какому поводу едете?', hint: 'От повода зависит, что важнее: площадка, парная или стол', opts: [
      { t: 'Семьёй с детьми', s: 'площадка и мелкая вода', ic: '<circle cx="12" cy="6" r="2"/><path d="M9 20v-5H7l2.5-5h5L17 15h-2v5"/>', p: { kedr: 3, sruba: 1 } },
      { t: 'Компанией друзей', s: 'баня, мангал, игры', ic: '<circle cx="7" cy="7.5" r="2.5"/><circle cx="17" cy="7.5" r="2.5"/><path d="M2 20c0-3 2.2-4.8 5-4.8M22 20c0-3-2.2-4.8-5-4.8M8 20h8"/>', p: { sruba: 3, banya: 3 } },
      { t: 'Вдвоём', s: 'тишина, вид на воду, купель', ic: '<path d="M12 20s-7-4.3-7-9a4 4 0 0 1 7-2.6A4 4 0 0 1 19 11c0 4.7-7 9-7 9z"/>', p: { kupol: 4, banya: 1 } },
      { t: 'Корпоратив или встреча', s: 'общий зал и парковка', ic: '<path d="M4 20V7h16v13M2 20h20M9 20v-4h6v4"/>', p: { prichal: 4, sruba: 1 } }
    ]},
    { tab: 'Что важно', q: 'Что должно быть на участке?', hint: 'Выберите то, без чего поездка теряет смысл', opts: [
      { t: 'Баня с настоящей парной', s: 'печь топим к приезду', ic: '<path d="M5 21V11l7-5 7 5v10zM9.5 16c0-1.5 1.5-2 1.5-3.5"/>', p: { banya: 4, sruba: 2 } },
      { t: 'Купель под открытым небом', s: 'греется за два часа', ic: '<path d="M4 12h16v4a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4zM9 9c0-1.5 1.5-2 1.5-3.5M14 9c0-1.5 1.5-2 1.5-3.5"/>', p: { kupol: 3, banya: 3 } },
      { t: 'Мангальная зона и беседка', s: 'стол на десять мест', ic: '<path d="M6 14h12l-1.5 6h-9zM4 14h16M10 11c0-1.6 1.5-2.2 1.5-3.8"/>', p: { sruba: 3, prichal: 3 } },
      { t: 'Тишина и лес вокруг', s: 'соседи за триста метров', ic: '<path d="M12 3l4 6h-3l4 6h-4l3 5H8l3-5H7l4-6H8z"/><path d="M12 20v2"/>', p: { kupol: 4, kedr: 2 } }
    ]},
    { tab: 'Срок', q: 'Сколько ночей планируете?', hint: 'От трёх ночей действует скидка на сутки', opts: [
      { t: 'Одну ночь', s: 'с пятницы на субботу', n: 1, ic: '<path d="M20 14a8 8 0 1 1-9.5-9.6A6.6 6.6 0 0 0 20 14z"/>', p: { kedr: 1, kupol: 1 } },
      { t: 'Две ночи', s: 'обычные выходные', n: 2, ic: '<path d="M5 5h14v14H5zM5 9h14M9 3v3M15 3v3"/>', p: { sruba: 1, banya: 1 } },
      { t: 'Три или четыре', s: 'длинные выходные', n: 3, ic: '<path d="M4 6h16v14H4zM4 10h16M8 3v4M16 3v4"/>', p: { banya: 2, kedr: 1 } },
      { t: 'Неделю и дольше', s: 'отпуск за городом', n: 7, ic: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>', p: { prichal: 2, sruba: 2 } }
    ]}
  ];

  /* ── ДОМА: cap - вместимость, day - цена за сутки ── */
  var HOUSES = {
    kupol: { ttl: 'Купол «Лесной»', cap: 2, day: 5400, href: '#dom-kupol',
      txt: 'Купол на опушке с панорамным окном в пол и кроватью напротив. Рядом кедровая купель и терраса, соседних домов из окна не видно.',
      has: ['Купель на дровах', 'Панорамное окно', 'Мангал'] },
    kedr: { ttl: 'Домик «Кедровый»', cap: 4, day: 7900, href: '#dom-kedrovyy',
      txt: 'Дом на 60 метров с двумя спальнями и кухней-гостиной. На участке качели, песочница и пологий спуск к воде, баня общая и топится по записи.',
      has: ['Две спальни', 'Детская площадка', 'Беседка'] },
    banya: { ttl: 'Дом «Банный»', cap: 6, day: 10800, href: '#dom-bannyy',
      txt: 'Парная стоит под одной крышей с домом, купель вынесена на террасу. Печь топят к приезду, три спальни наверху, внизу гостиная со столом.',
      has: ['Своя парная', 'Купель на террасе', 'Три спальни'] },
    sruba: { ttl: 'Сруб «Березняк»', cap: 8, day: 12600, href: '#dom-bereznyak',
      txt: 'Сруб с четырьмя спальнями и гостиной на первом этаже. Во дворе крытая беседка со столом на десять человек, мангал и дровяник.',
      has: ['Четыре спальни', 'Беседка на 10 мест', 'Баня рядом'] },
    prichal: { ttl: 'Большой дом «Причал»', cap: 12, day: 19400, href: '#dom-prichal',
      txt: 'Дом на двенадцать гостей с залом, шестью спальнями и второй кухней. У воды свой настил с мостками, берут под дни рождения и выезды отделов.',
      has: ['Зал на 20 человек', 'Шесть спален', 'Мостки у воды'] }
  };

  var roots = document.querySelectorAll('.vbkpo');
  for (var i = 0; i < roots.length; i++) init(roots[i]);

  function init(root) {
    if (root.__vb) return; root.__vb = 1;
    var stage = root.querySelector('#vbkpo-stage'), tabs = root.querySelector('#vbkpo-steps');
    var back = root.querySelector('#vbkpo-back'), num = root.querySelector('#vbkpo-num');
    var idx = 0, score = {}, need = 2, nights = 2, trail = [];

    function ic(d) {
      return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" ' +
        'stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">' + d + '<\/g><\/svg>';
    }
    function fmt(n) { return String(Math.round(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ' '); }
    function reset() { score = { kupol: 0, kedr: 0, banya: 0, sruba: 0, prichal: 0 }; need = 2; nights = 2; trail = []; }

    function drawTabs(done) {
      var out = '';
      for (var s = 0; s < STEPS.length; s++) {
        var cls = s === idx && !done ? ' class="vbkpo-on"' : (s < idx || done ? ' class="vbkpo-done"' : '');
        out += '<li' + cls + '>' + STEPS[s].tab + '<\/li>';
      }
      tabs.innerHTML = out;
    }

    function drawStep() {
      var st = STEPS[idx];
      drawTabs(false);
      num.textContent = 'Шаг ' + (idx + 1) + ' из ' + STEPS.length;
      back.hidden = idx === 0;
      var out = '<h3 class="vbkpo-q">' + st.q + '<\/h3><p class="vbkpo-hint">' + st.hint + '<\/p><div class="vbkpo-opts">';
      for (var o = 0; o < st.opts.length; o++) {
        var op = st.opts[o];
        out += '<button type="button" class="vbkpo-opt" data-i="' + o + '">' + ic(op.ic) +
          '<span><b>' + op.t + '<\/b><i>' + op.s + '<\/i><\/span><\/button>';
      }
      stage.innerHTML = out + '<\/div>';
      var btns = stage.querySelectorAll('.vbkpo-opt');
      for (var b = 0; b < btns.length; b++) {
        btns[b].addEventListener('click', function () {
          var op = STEPS[idx].opts[+this.getAttribute('data-i')];
          trail.push({ p: op.p, k: op.k, n: op.n, prevK: need, prevN: nights });
          for (var key in op.p) { if (op.p.hasOwnProperty(key)) score[key] += op.p[key]; }
          if (op.k) need = op.k;
          if (op.n) nights = op.n;
          idx++;
          if (idx < STEPS.length) drawStep(); else drawResult();
        });
      }
    }

    function drawResult() {
      drawTabs(true);
      num.textContent = 'Подбор готов';
      back.hidden = false;
      var keys = [], k;
      for (k in HOUSES) { if (HOUSES.hasOwnProperty(k) && HOUSES[k].cap >= need) keys.push(k); }
      if (!keys.length) keys = ['prichal'];
      keys.sort(function (a, b) {
        if (score[b] !== score[a]) return score[b] - score[a];
        return HOUSES[a].cap - HOUSES[b].cap;
      });
      var h = HOUSES[keys[0]];
      var total = h.day * nights * (nights >= 3 ? 0.9 : 1);
      var word = nights === 1 ? 'ночь' : (nights < 5 ? 'ночи' : 'ночей');

      var out = '<div class="vbkpo-res"><span class="vbkpo-res__tag">' + ic('<path d="M5 13l4 4L19 7"/>') + 'Подходит по вашим ответам<\/span>' +
        '<h3 class="vbkpo-res__ttl">' + h.ttl + '<\/h3><p class="vbkpo-res__txt">' + h.txt + '<\/p>' +
        '<div class="vbkpo-res__grid"><div><b>' + fmt(h.day) + ' ₽<\/b><span>за сутки в будни<\/span><\/div>' +
        '<div><b>до ' + h.cap + ' гостей<\/b><span>спальных мест столько же<\/span><\/div>' +
        '<div><b>' + fmt(total) + ' ₽<\/b><span>' + nights + ' ' + word + ' с учётом скидки<\/span><\/div><\/div><ul class="vbkpo-res__has">';
      for (var i2 = 0; i2 < h.has.length; i2++) out += '<li>' + h.has[i2] + '<\/li>';
      out += '<\/ul><div class="vbkpo-acts"><a class="vbkpo-cta" href="' + h.href + '">Смотреть свободные даты<\/a>' +
        '<button type="button" class="vbkpo-again">Пройти заново<\/button><\/div><\/div>';
      stage.innerHTML = out;
      var again = stage.querySelector('.vbkpo-again');
      if (again) again.addEventListener('click', function () { idx = 0; reset(); drawStep(); });
    }

    back.addEventListener('click', function () {
      if (idx === 0) return;
      idx--;
      var last = trail.pop();
      if (last) {
        for (var key in last.p) { if (last.p.hasOwnProperty(key)) score[key] -= last.p[key]; }
        need = last.prevK; nights = last.prevN;
      }
      drawStep();
    });

    reset();
    drawStep();
  }
})();
</script>

Вставляется целиком в блок T123 «HTML-код». Внутри уже есть стили и скрипт, подключать ничего не нужно.

Как вставить блок в Tilda

  1. Скопируйте кодКнопка «Скопировать код» выше кладёт всё содержимое в буфер обмена.
  2. Добавьте блок T123В редакторе страницы: «Библиотека блоков» → «Другое» → T123 «HTML-код».
  3. Вставьте и сохранитеНажмите «Контент», вставьте код в поле, сохраните и обновите страницу.
  4. ОпубликуйтеВ превью скрипты Tilda работают не всегда — проверяйте на опубликованной странице.

Подробная инструкция с граблями — как вставить вайб-блок в Tilda.

Что менять под себя

Где в кодеЗа что отвечает
STEPS в начале скриптавопросы, подсказки, варианты ответов и очки за каждый вариант
ключ k у первого шагакакая вместимость требуется после этого ответа
HOUSES ниженазвания домов, цена за сутки, вместимость, описание и чипы удобств
множитель 0.9 в drawResultразмер скидки при сроке от трёх ночей
href у каждого домаадрес страницы или якорь конкретного дома

Квиз подбора дома для отдыха: зачем он нужен

Первый вопрос задаёт размер компании и сразу отсекает дома, куда столько гостей не поместится. Дальше идут повод поездки, обязательное удобство на участке и число ночей. Каждый вариант ответа несёт очки пяти домам: купол глэмпинга, домик для семьи, сруб с парной, большой сруб и дом на двенадцать гостей. Наверху стоит полоса из четырёх подписанных шагов, внизу счётчик и ссылка на предыдущий вопрос с откатом набранных очков.

Результат выбирается в два приёма: сначала остаются дома нужной вместимости, затем среди них берётся тот, кто набрал больше очков. В карточке ответа стоят цена за сутки, вместимость и сумма за выбранное число ночей со скидкой от трёх ночей. Ниже идут чипы с тем, что есть в доме, и две кнопки: перейти к датам этого дома и пройти квиз заново. Данные никуда не отправляются, весь подсчёт живёт в браузере.

Вопросы по этому блоку

  • Впишите новый объект в HOUSES с полями cap, day, txt и has, а затем раздайте ему очки в нужных вариантах ответов. Ничего больше править не требуется, отбор идёт по вместимости и сумме очков.

  • Скрипт покажет самый большой дом из списка. Если у вас есть вариант с двумя домами рядом, добавьте его в HOUSES с нужной вместимостью и опишите условие в тексте.

  • Да, удалите последний объект из STEPS. Расчёт за все ночи возьмёт значение по умолчанию, оно задано переменной nights в начале функции init.

  • Да. Код на этой странице копируется целиком, без регистрации и подписки. Указывать авторство не нужно, использовать можно в коммерческих проектах.

  • Нет. Все классы внутри имеют собственный префикс vbkpo, поэтому не пересекаются ни со стилями Tilda, ни с другими блоками. Скрипт привязан к своему элементу и запускается один раз, даже если блок вставлен дважды.

  • Раскладка перестраивается под узкие экраны, размеры заданы через clamp, поля ввода имеют шрифт 16 пикселей — iOS не будет зумить страницу при фокусе. Отдельной мобильной версии подключать не нужно.

Другие квизы

Ещё блоки для аренды домов

Собрать сайт целиком, а не по блокам

Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса.