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

Отзывы гостей базы отдыха

Лента отзывов в три колонки: в карточке видно, кто приезжал, каким составом, в каком доме и в каком сезоне, а чипы сверху оставляют отзывы нужного времени года.

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

Код блока

<section class="vbogb">
  <div class="vbogb-wrap">
    <div class="vbogb-top">
      <div class="vbogb-head">
        <h2 class="vbogb-h2">Гости о домах и территории</h2>
        <p class="vbogb-lead">Анкету присылаем на второй день после выезда. В карточке видно, какой дом снимали, в каком сезоне и с кем приезжали, поэтому отзыв легко примерить на свою поездку.</p>
      </div>
      <div class="vbogb-score">
        <b id="vbogb-avg">0,0</b>
        <div>
          <span class="vbogb-stars" id="vbogb-top-stars" role="img" aria-label="Средняя оценка гостей"></span>
          <span class="vbogb-score__t" id="vbogb-cnt"></span>
        </div>
      </div>
    </div>

    <div class="vbogb-chips" id="vbogb-chips" role="group" aria-label="Отбор отзывов по сезону"></div>
    <div class="vbogb-feed" id="vbogb-feed"></div>
    <p class="vbogb-empty" id="vbogb-empty" hidden>За этот сезон отзывов пока нет, выберите другой.</p>
  </div>
</section>

<style>
.vbogb, .vbogb *, .vbogb *::before, .vbogb *::after { box-sizing: border-box; }
.vbogb {
  --acc: #4f7d43; --star: #d8a13c; --ink: #1e2a20; --muted: #63755f; --line: #e0e8d9; --soft: #f4f8ef;
  --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;
}
.vbogb-wrap { max-width: 1220px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbogb-top { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: clamp(20px, 3vw, 44px); align-items: end; margin-bottom: clamp(20px, 2.6vw, 30px); }
.vbogb-head { max-width: 44em; }
.vbogb-h2 { font-family: var(--fh); font-size: clamp(25px, 3.3vw, 40px); line-height: 1.1; font-weight: 700; letter-spacing: -.022em; margin: 0 0 12px; }
.vbogb-lead { font-size: 16px; line-height: 1.6; color: var(--muted); margin: 0; }

.vbogb-score { display: flex; align-items: center; gap: 14px; background: var(--soft); border-radius: 20px; padding: 18px 22px; }
.vbogb-score b { font-family: var(--fh); font-size: clamp(34px, 4vw, 46px); line-height: 1; font-weight: 700; color: var(--acc); }
.vbogb-score__t { display: block; font-size: 12.5px; line-height: 1.45; color: var(--muted); margin-top: 6px; max-width: 15em; }
.vbogb-stars { display: inline-flex; gap: 2px; }
.vbogb-stars svg { width: 16px; height: 16px; color: #d3ddca; }
.vbogb-stars svg.vbogb-on { color: var(--star); }

.vbogb-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: clamp(16px, 2vw, 24px); }
.vbogb-chip { -webkit-appearance: none; appearance: none; margin: 0; padding: 11px 18px; border: 1.5px solid var(--line); border-radius: 999px;
  cursor: pointer; font: inherit; font-size: 14px; background: #fff !important; color: var(--muted) !important; transition: .18s ease; }
.vbogb-chip:hover { border-color: var(--acc); color: var(--ink) !important; }
.vbogb-chip i { font-style: normal; opacity: .65; margin-left: 6px; }
.vbogb-chip--on, .vbogb-chip--on:hover { background: var(--acc) !important; border-color: var(--acc); color: #fff !important; font-weight: 600; }

.vbogb-feed { column-count: 3; column-gap: clamp(12px, 1.6vw, 20px); }
.vbogb-card { break-inside: avoid; page-break-inside: avoid; border: 1px solid var(--line); border-radius: 20px;
  padding: 22px 24px; margin: 0 0 clamp(12px, 1.6vw, 20px); background: #fff; }
.vbogb-card__top { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.vbogb-ava { flex: 0 0 42px; width: 42px; height: 42px; 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); }
.vbogb-card__n { display: block; font-size: 15px; font-weight: 600; }
.vbogb-card__w { display: block; font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.vbogb-card__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.vbogb-tag { font-size: 11.5px; color: var(--acc); background: var(--soft); border-radius: 999px; padding: 5px 11px; }
.vbogb-tag--season { color: #8a6a2c; background: #faf3e6; }
.vbogb-card p { margin: 0; font-size: 14.5px; line-height: 1.65; color: var(--muted); }
.vbogb-empty { margin: 0; font-size: 15px; color: var(--muted); }

@media (max-width: 1000px) { .vbogb-feed { column-count: 2; } }
@media (max-width: 860px) { .vbogb-top { grid-template-columns: minmax(0, 1fr); align-items: start; } }
@media (max-width: 620px) { .vbogb-feed { column-count: 1; } }
@media (prefers-reduced-motion: reduce) { .vbogb * { transition: none !important; } }
</style>

<script>
(function () {
  /* ── ОТЗЫВЫ: who - с кем приезжали, house - дом, season - сезон, rate - звёзды ── */
  var REVIEWS = [
    { name: 'Ирина и Павел', who: 'вдвоём на годовщину', house: 'Купол «Лесной»', season: 'Зима', rate: 5,
      text: 'Брали купол на две ночи в конце января. Снег вокруг, панорамное окно от пола, вечером топили купель и сидели в ней под фонарём. Дорогу до самого дома чистят, легковая машина прошла без вопросов.' },
    { name: 'Семья Кузнецовых', who: 'с двумя детьми 5 и 9 лет', house: 'Домик «Кедровый»', season: 'Лето', rate: 5,
      text: 'Спуск к воде пологий, мелко далеко от берега, поэтому за детьми можно смотреть с террасы. Качели и песочница заняли младшего на весь день. Посуды хватило, готовили сами, в магазин ездили в село за десять минут.' },
    { name: 'Денис Р.', who: 'компанией из шести человек', house: 'Дом «Банный»', season: 'Осень', rate: 5,
      text: 'Печь протопили к нашему приезду, в парной было ровно то, что нужно после дороги. Веники и дрова лежали в предбаннике. Единственное, о чём стоит знать: купель на террасе греется дольше, чем кажется, лучше сказать про неё заранее.' },
    { name: 'Марина Т.', who: 'выезд отдела, 11 человек', house: 'Большой дом «Причал»', season: 'Весна', rate: 4,
      text: 'Зал вместил всех, для ноутбуков хватило розеток, интернет держал видеосвязь. Из минусов: вторая кухня маленькая для такой компании, готовить на одиннадцать человек в ней тесно. Мангальную зону администратор подготовил заранее.' },
    { name: 'Алексей и Ольга', who: 'вдвоём с собакой', house: 'Домик «Кедровый»', season: 'Осень', rate: 5,
      text: 'Приятно, что про питомца спросили при бронировании и назвали цену сразу, а на месте выдали миски и коврик. Территория огорожена, поэтому пса отпускали побегать. Соседний дом стоял пустой, тишина полная.' },
    { name: 'Гости из Тюмени', who: 'три пары друзей', house: 'Сруб «Березняк»', season: 'Лето', rate: 5,
      text: 'Беседка со столом на десять мест решает всё: ужинали там три вечера подряд. Дрова колотые, разжигается быстро, мангал большой. Утром доносился только звук с воды. Приедем той же компанией в июле.' },
    { name: 'Виктор С.', who: 'с родителями и сестрой', house: 'Сруб «Березняк»', season: 'Зима', rate: 4,
      text: 'Дом тёплый, полы с подогревом в санузле, на втором этаже прохладнее градуса на три. Родителям было удобно на первом. Выезд продлили до трёх часов дня, доплату посчитали ровно по прайсу без разговоров.' },
    { name: 'Екатерина Л.', who: 'вдвоём с подругой', house: 'Купол «Лесной»', season: 'Весна', rate: 5,
      text: 'Ехали смотреть на ледоход и остались довольны видом. Завтраки заказывали оба утра, привозили к девяти, сырники тёплые. Чек прислали на почту в тот же день, залог вернули при выезде наличными.' }
  ];

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

  function init(root) {
    if (root.__vb) return; root.__vb = 1;
    var feed = root.querySelector('#vbogb-feed'), chips = root.querySelector('#vbogb-chips');
    var empty = root.querySelector('#vbogb-empty'), cur = 'Все';

    function stars(r) {
      var out = '<span class="vbogb-stars" role="img" aria-label="Оценка ' + r + ' из 5">';
      for (var s = 1; s <= 5; s++) {
        out += '<svg viewBox="0 0 20 20" class="' + (s <= r ? 'vbogb-on' : '') + '" aria-hidden="true" focusable="false">' +
          '<path fill="currentColor" d="M10 1.6l2.5 5.2 5.7.8-4.1 4 1 5.7-5.1-2.7-5.1 2.7 1-5.7-4.1-4 5.7-.8z"/><\/svg>';
      }
      return out + '<\/span>';
    }

    var sum = 0, order = ['Все', 'Зима', 'Весна', 'Лето', 'Осень'], counts = { 'Все': REVIEWS.length };
    for (var r1 = 0; r1 < REVIEWS.length; r1++) {
      sum += REVIEWS[r1].rate;
      counts[REVIEWS[r1].season] = (counts[REVIEWS[r1].season] || 0) + 1;
    }
    var avg = sum / REVIEWS.length;
    root.querySelector('#vbogb-avg').textContent = avg.toFixed(1).replace('.', ',');
    root.querySelector('#vbogb-top-stars').innerHTML = stars(Math.round(avg));
    root.querySelector('#vbogb-cnt').textContent = 'средняя оценка по ' + REVIEWS.length + ' анкетам за последний год';

    var chipHtml = '';
    for (var c = 0; c < order.length; c++) {
      if (!counts[order[c]]) continue;
      chipHtml += '<button type="button" class="vbogb-chip' + (order[c] === cur ? ' vbogb-chip--on' : '') +
        '" data-s="' + order[c] + '">' + order[c] + '<i>' + counts[order[c]] + '<\/i><\/button>';
    }
    chips.innerHTML = chipHtml;

    function draw() {
      var out = '', shown = 0;
      for (var n = 0; n < REVIEWS.length; n++) {
        var rv = REVIEWS[n];
        if (cur !== 'Все' && rv.season !== cur) continue;
        shown++;
        out += '<article class="vbogb-card"><div class="vbogb-card__top">' +
          '<span class="vbogb-ava">' + rv.name.charAt(0) + '<\/span>' +
          '<span><b class="vbogb-card__n">' + rv.name + '<\/b>' +
          '<span class="vbogb-card__w">' + rv.who + '<\/span><\/span><\/div>' +
          '<div class="vbogb-card__meta"><span class="vbogb-tag">' + rv.house + '<\/span>' +
          '<span class="vbogb-tag vbogb-tag--season">' + rv.season + '<\/span>' + stars(rv.rate) + '<\/div>' +
          '<p>' + rv.text + '<\/p><\/article>';
      }
      feed.innerHTML = out;
      empty.hidden = shown > 0;
    }

    var btns = chips.querySelectorAll('.vbogb-chip');
    for (var b = 0; b < btns.length; b++) {
      btns[b].addEventListener('click', function () {
        for (var k = 0; k < btns.length; k++) btns[k].className = 'vbogb-chip';
        this.className = 'vbogb-chip vbogb-chip--on';
        cur = this.getAttribute('data-s');
        draw();
      });
    }

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

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

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

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

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

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

Где в кодеЗа что отвечает
REVIEWS в начале скриптаимя, состав компании, дом, сезон, оценка и текст каждого отзыва
массив order в функции initпорядок и набор чипов отбора по сезонам
текст в vbogb-cntподпись под средней оценкой про число анкет и период
column-count у лентысколько колонок держать на широком экране
--star в начале стилейцвет закрашенных звёзд в оценке

Отзывы гостей базы отдыха: зачем он нужен

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

Карточки выложены в три колонки потоком, поэтому короткие и длинные отзывы стоят рядом без пустот, а на планшете колонок становится две, на телефоне одна. Оценка нарисована пятью звёздами векторной графикой, закрашенные и пустые отличаются цветом. Если в выбранном сезоне отзывов нет, вместо ленты появляется спокойная строка с подсказкой. Тексты отзывов лежат массивом REVIEWS в начале скрипта.

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

  • Да, поменяйте поле season на house в условии отбора и подставьте в массив order названия домов. Счётчики в чипах соберутся по тому же полю.

  • Скрипт складывает поле rate всех отзывов и делит на их число, затем округляет до одного знака и меняет точку на запятую. Отдельно вписывать её не нужно.

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

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

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

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

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

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

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

Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса. Как это выглядит для ниши «Аренда домов и отдых», видно на отдельной странице.