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

Отзывы заказчиков о строительстве дома

Плитки отзывов, где рядом с текстом вынесены объект, срок стройки и строка про смету. Сверху стоит фильтр по материалу стен: каркас, газобетон, брус.

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

Код блока

<section class="vbozd">
  <div class="vbozd-wrap">
    <div class="vbozd-head">
      <div>
        <h2 class="vbozd-h2">Что говорят заказчики после новоселья</h2>
        <p class="vbozd-lead">Собираем отзывы через полгода после передачи ключей, когда дом уже прошёл первую зиму. Указываем, что построили, сколько это заняло и попали ли в смету.</p>
      </div>
      <div class="vbozd-score">
        <b>32</b>
        <span>дома сдали за прошлый сезон, 29 из них в срок по договору</span>
      </div>
    </div>

    <div class="vbozd-tabs" id="vbozd-tabs"></div>
    <div class="vbozd-grid" id="vbozd-grid"></div>
  </div>
</section>

<style>
.vbozd, .vbozd *, .vbozd *::before, .vbozd *::after { box-sizing: border-box; }
.vbozd {
  --acc: #3f6b52; --acc-dark: #325741; --ink: #1d211e; --muted: #666e68; --line: #e0e5e0; --soft: #f2f6f2; --warn: #a8611f;
  --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;
}
.vbozd-wrap { max-width: 1240px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbozd-head { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, .65fr); gap: clamp(20px, 3vw, 44px);
  align-items: end; margin-bottom: clamp(24px, 3vw, 38px); }
.vbozd-h2 { font-family: var(--fh); font-size: clamp(26px, 3.4vw, 42px); line-height: 1.1; font-weight: 700; letter-spacing: -.022em; margin: 0 0 12px; }
.vbozd-lead { font-size: 16px; line-height: 1.6; color: var(--muted); margin: 0; max-width: 40em; }
.vbozd-score { display: flex; align-items: center; gap: 16px; background: var(--soft); border-radius: 18px; padding: 20px 22px; }
.vbozd-score b { font-family: var(--fh); font-size: 44px; line-height: 1; font-weight: 700; color: var(--acc); }
.vbozd-score span { font-size: 13.5px; line-height: 1.45; color: var(--muted); }

.vbozd-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.vbozd-tab { border: 1.5px solid var(--line); margin: 0; padding: 10px 18px; -webkit-appearance: none; appearance: none;
  font: inherit; font-size: 14.5px; cursor: pointer; border-radius: 999px;
  background: #fff !important; color: var(--ink) !important; transition: .18s ease; }
.vbozd-tab:hover { border-color: var(--acc); }
.vbozd-tab--on, .vbozd-tab--on:hover { background: var(--acc) !important; border-color: var(--acc); color: #fff !important; }

.vbozd-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; align-items: start; }
.vbozd-card { border: 1px solid var(--line); border-radius: 18px; padding: 22px 24px; }
.vbozd-card__top { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.vbozd-ava { flex: 0 0 44px; width: 44px; height: 44px; border-radius: 14px; background: var(--soft); display: flex; align-items: center;
  justify-content: center; font-family: var(--fh); font-size: 16px; font-weight: 700; color: var(--acc); }
.vbozd-card__n { display: block; font-size: 15.5px; font-weight: 600; }
.vbozd-card__o { display: block; font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.vbozd-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-bottom: 14px; }
.vbozd-meta div { background: var(--soft); border-radius: 11px; padding: 10px 13px; }
.vbozd-meta span { display: block; font-size: 11.5px; color: var(--muted); }
.vbozd-meta b { display: block; font-size: 13.5px; font-weight: 600; margin-top: 3px; }
.vbozd-meta b.vbozd-over { color: var(--warn); }
.vbozd-card p { margin: 0; font-size: 14.8px; line-height: 1.68; color: var(--muted); }
.vbozd-empty { grid-column: 1 / -1; font-size: 15px; color: var(--muted); padding: 22px 0; margin: 0; }

@media (max-width: 900px) { .vbozd-head { grid-template-columns: minmax(0, 1fr); align-items: start; } }
@media (max-width: 400px) { .vbozd-meta { grid-template-columns: minmax(0, 1fr); } }
@media (prefers-reduced-motion: reduce) { .vbozd * { transition: none !important; } }
</style>

<script>
(function () {
  /* ── ОТЗЫВЫ: mat это материал для фильтра, fit это попадание в смету ── */
  var REVIEWS = [
    { name: 'Андрей и Мария Ковалёвы', mat: 'frame', obj: 'Каркасный дом 120 м², посёлок Ольгино',
      term: '4 месяца', fit: 'Смета без изменений',
      text: 'Договорились в феврале, ключи получили в июне. Раз в неделю приезжал наш инженер и присылал фотографии по этапам, поэтому мы спокойно жили в городе и не караулили стройку. Итог совпал со сметой до рубля, доплачивали только за розетки сверх проекта.' },
    { name: 'Сергей Литвинов', mat: 'gas', obj: 'Газобетон 160 м², Всеволожский район',
      term: '7 месяцев', fit: 'Смета выросла на 4%',
      text: 'Геология показала глину с высокой водой, поэтому вместо ленты делали плиту. Разницу посчитали заранее и показали расчёт, я согласовал письменно. Дом прошёл вторую зиму, по стенам трещин нет, счёт за газ за январь вышел 4 700 рублей.' },
    { name: 'Ольга Терентьева', mat: 'brus', obj: 'Дом из бруса 96 м², Приозерское шоссе',
      term: '5 месяцев', fit: 'Смета без изменений',
      text: 'Хотела деревянный дом и боялась историй про усадку. Бригадир объяснил, почему чистовые работы начнём через полгода, и мы заложили это в график сразу. Год прошёл, зазоры компенсировались винтами, двери открываются нормально.' },
    { name: 'Дмитрий Савчук', mat: 'gas', obj: 'Газобетон 186 м² с гаражом, Токсово',
      term: '9 месяцев', fit: 'Смета выросла на 2%',
      text: 'Строили с зимним перерывом на кладку. Понравилось, что каждый этап закрывали актом и я платил после приёмки. Один раз ошиблись с высотой проёма под входную дверь, переделали за свой счёт за три дня и не спорили.' },
    { name: 'Ирина и Павел Носовы', mat: 'frame', obj: 'Каркасный дом 78 м², Синявино',
      term: '3 месяца', fit: 'Смета без изменений',
      text: 'Бюджет был жёсткий, поэтому выбрали тёплый контур и отделку делали сами следующей весной. Нам подробно расписали, что входит в контур и чего ждать дальше. Разводку электрики оставили с запасом под будущую кухню.' },
    { name: 'Виктор Хомяков', mat: 'brus', obj: 'Брус 132 м², Лужский район',
      term: '6 месяцев', fit: 'Смета выросла на 3%',
      text: 'Участок в 90 километрах от города, доставка бруса вышла дороже расчёта, о чём предупредили до подписания. По самой сборке вопросов нет, венцы легли ровно, щелей после первой зимы не появилось. Документы передали полным комплектом.' }
  ];

  /* ── ФИЛЬТРЫ ── */
  var TABS = [
    { k: 'all', t: 'Все дома' },
    { k: 'frame', t: 'Каркас' },
    { k: 'gas', t: 'Газобетон' },
    { k: 'brus', t: 'Брус' }
  ];

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

  function init(root) {
    if (root.__vb) return; root.__vb = 1;
    var tabsBox = root.querySelector('#vbozd-tabs'), grid = root.querySelector('#vbozd-grid');
    var cur = 'all';

    var th = '';
    for (var t = 0; t < TABS.length; t++) {
      th += '<button type="button" class="vbozd-tab' + (TABS[t].k === cur ? ' vbozd-tab--on' : '') +
        '" data-k="' + TABS[t].k + '">' + TABS[t].t + '<\/button>';
    }
    tabsBox.innerHTML = th;

    var btns = tabsBox.querySelectorAll('.vbozd-tab');
    for (var b = 0; b < btns.length; b++) bind(btns[b]);

    function bind(btn) {
      btn.addEventListener('click', function () {
        cur = btn.getAttribute('data-k');
        for (var j = 0; j < btns.length; j++) {
          btns[j].className = 'vbozd-tab' + (btns[j] === btn ? ' vbozd-tab--on' : '');
        }
        draw();
      });
    }

    function draw() {
      var html = '', shown = 0, r;
      for (var n = 0; n < REVIEWS.length; n++) {
        r = REVIEWS[n];
        if (cur !== 'all' && r.mat !== cur) continue;
        shown++;
        html += '<article class="vbozd-card"><div class="vbozd-card__top">' +
          '<span class="vbozd-ava">' + r.name.charAt(0) + '<\/span>' +
          '<span><b class="vbozd-card__n">' + r.name + '<\/b>' +
          '<span class="vbozd-card__o">' + r.obj + '<\/span><\/span><\/div>' +
          '<div class="vbozd-meta"><div><span>Срок стройки<\/span><b>' + r.term + '<\/b><\/div>' +
          '<div><span>Бюджет<\/span><b class="' + (r.fit.indexOf('выросла') > -1 ? 'vbozd-over' : '') + '">' + r.fit + '<\/b><\/div><\/div>' +
          '<p>' + r.text + '<\/p><\/article>';
      }
      if (!shown) html = '<p class="vbozd-empty">По этому материалу отзывов пока нет.<\/p>';
      grid.innerHTML = html;
    }

    draw();
  }
})();
</script>

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

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

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

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

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

Где в кодеЗа что отвечает
массив REVIEWSотзывы: имя, объект, срок стройки, попадание в смету, текст
массив TABSкнопки фильтра по материалу стен
цифру в плашке сверхусколько домов сдали за сезон и сколько из них в срок
--acc и --warnцвет активного фильтра и подсветка превышения сметы

Отзывы заказчиков о доме: зачем он нужен

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

Над плитками стоит фильтр по материалу стен, чтобы посетитель с каркасным домом читал именно про каркас. Все отзывы лежат в массиве REVIEWS в начале скрипта: имя, ключ материала, объект, срок, строка про смету и текст. Кнопки фильтра строятся из массива TABS, поэтому добавить материал это дописать одну строку. Если по выбранному фильтру записей нет, блок покажет короткое сообщение вместо пустой сетки.

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

  • Допишите объект в массив REVIEWS. Поле с материалом должно совпадать с ключом одной из кнопок фильтра, иначе отзыв будет виден только на вкладке со всеми домами.

  • Да. Оставьте в массиве TABS один элемент с ключом all, тогда останется одна кнопка. Либо скройте контейнер фильтра стилем display none, сетка отзывов продолжит работать.

  • Скрипт берёт первую букву из поля с именем. Если нужны фотографии, замените элемент с классом vbozd-ava на картинку, загруженную в файлы Tilda.

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

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

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

Другие блоки отзывов

Ещё блоки для строительства домов

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

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