Блок отзывов работодателей для кадрового агентства
Плитки отзывов от компаний: сфера, закрытые позиции, число вышедших людей и срок подбора, фильтр по формату услуги и две сводные цифры над лентой.
<section class="vbor">
<div class="vbor-wrap">
<div class="vbor-head">
<div>
<h2 class="vbor-h2">Что говорят компании, которым мы искали людей</h2>
<p class="vbor-lead">Отзывы собраны после закрытия заявки и подтверждены подписанными актами. Указываем позиции, число вышедших людей и срок работы по каждой заявке.</p>
</div>
<ul class="vbor-sum" id="vbor-sum"></ul>
</div>
<div class="vbor-filter" id="vbor-filter"></div>
<div class="vbor-grid" id="vbor-grid" aria-live="polite"></div>
<p class="vbor-count" id="vbor-count"></p>
</div>
</section>
<style>
.vbor, .vbor *, .vbor *::before, .vbor *::after { box-sizing: border-box; }
.vbor {
--acc: #2e6f9e; --ink: #16202b; --muted: #5c6a7a; --line: #e0e6ec; --soft: #f1f5f8;
--f: var(--t-text-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif);
--fh: var(--t-headline-font, var(--f));
background: #f7f9fb; color: var(--ink); font-family: var(--f); padding: clamp(36px, 5vw, 80px) 20px;
}
.vbor-wrap { max-width: 1220px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbor-head { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, .75fr); gap: clamp(22px, 3vw, 48px); align-items: end; margin-bottom: clamp(22px, 3vw, 34px); }
.vbor-h2 { font-family: var(--fh); font-size: clamp(26px, 3.4vw, 42px); line-height: 1.1; font-weight: 700; letter-spacing: -.02em; margin: 0 0 12px; }
.vbor-lead { font-size: 16px; line-height: 1.62; color: var(--muted); margin: 0; max-width: 38em; }
.vbor-sum { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.vbor-sum li { background: #fff; border: 1px solid var(--line); border-radius: 16px; padding: 16px 18px; }
.vbor-sum b { display: block; font-family: var(--fh); font-size: 24px; line-height: 1.05; font-weight: 700; color: var(--acc); letter-spacing: -.02em; }
.vbor-sum span { display: block; font-size: 12px; line-height: 1.45; color: var(--muted); margin-top: 5px; }
.vbor-filter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.vbor-chip { border: 1px solid var(--line); margin: 0; padding: 11px 18px; -webkit-appearance: none; appearance: none; font: inherit; font-size: 14px;
cursor: pointer; border-radius: 999px; background: #fff !important; color: var(--muted) !important; transition: .18s ease; }
.vbor-chip:hover { border-color: var(--acc); color: var(--ink) !important; }
.vbor-chip[aria-pressed="true"] { background: var(--acc) !important; color: #fff !important; border-color: var(--acc); }
.vbor-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; }
.vbor-card { display: flex; flex-direction: column; background: #fff; border: 1px solid var(--line); border-radius: 20px; padding: clamp(20px, 2.2vw, 26px);
opacity: 0; transform: translateY(10px); animation: vbor-in .35s ease forwards; }
.vbor-card__top { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.vbor-mark { flex: 0 0 44px; width: 44px; height: 44px; border-radius: 13px; background: var(--soft); display: flex; align-items: center; justify-content: center;
font-family: var(--fh); font-size: 16px; font-weight: 700; color: var(--acc); }
.vbor-co { display: block; font-size: 15.5px; font-weight: 600; line-height: 1.3; }
.vbor-field { display: block; font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.vbor-roles { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.vbor-roles li { font-size: 12px; color: var(--muted); background: var(--soft); border-radius: 8px; padding: 6px 10px; }
.vbor-card p { margin: 0 0 18px; font-size: 14.5px; line-height: 1.65; color: var(--muted); }
.vbor-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: auto; border-top: 1px solid var(--line); padding-top: 16px; }
.vbor-facts b { display: block; font-family: var(--fh); font-size: 17px; font-weight: 700; line-height: 1.15; }
.vbor-facts span { display: block; font-size: 11.5px; color: var(--muted); margin-top: 4px; }
.vbor-who { font-size: 12.5px; color: var(--muted); margin-top: 14px; }
.vbor-count { font-size: 13px; color: var(--muted); margin: 18px 0 0; }
@keyframes vbor-in { to { opacity: 1; transform: none; } }
@media (max-width: 900px) { .vbor-head { grid-template-columns: minmax(0, 1fr); align-items: start; } }
@media (prefers-reduced-motion: reduce) { .vbor * { transition: none !important; animation: none !important; opacity: 1 !important; transform: none !important; } }
</style>
<script>
(function () {
/* ── ФОРМАТЫ ДЛЯ ФИЛЬТРА ── */
var TABS = [
{ k: 'all', n: 'Все заявки' },
{ k: 'mass', n: 'Массовый подбор' },
{ k: 'spot', n: 'Специалисты' },
{ k: 'exec', n: 'Руководители' },
{ k: 'staff', n: 'Аутстаффинг' }
];
/* ── ОТЗЫВЫ РАБОТОДАТЕЛЕЙ ── */
var REVIEWS = [
{ co: 'Сеть пекарен «Тёплый угол»', kind: 'mass', field: 'Общественное питание, 24 точки',
roles: ['Пекарь', 'Продавец', 'Помощник кондитера'], people: 34, days: 26, who: 'Ирина Соколова, руководитель отдела персонала',
txt: 'Открывали шесть точек за квартал и своими силами не успевали. Агентство вело поток кандидатов и присылало сводку каждый вечер, поэтому мы понимали, где просядем по срокам. Из 34 вышедших к концу испытательного срока остались 30.' },
{ co: 'Завод «Промлит»', kind: 'spot', field: 'Металлообработка, 340 сотрудников',
roles: ['Инженер-технолог', 'Мастер участка'], people: 3, days: 21, who: 'Андрей Лапшин, директор по производству',
txt: 'Технолога с опытом литья под давлением искали своими силами полгода. Здесь показали пятерых за три недели, двое подошли по задачам сразу. Понравилось, что рекрутер приезжал на завод и разбирался в участке до старта поиска.' },
{ co: 'Логистический оператор «Стрелец»', kind: 'staff', field: 'Склады класса А, три площадки',
roles: ['Комплектовщик', 'Водитель погрузчика'], people: 62, days: 4, who: 'Марина Гущина, управляющая складом',
txt: 'Перед высоким сезоном нужна была дополнительная смена. Люди вышли на четвёртый день после заявки, оформление и выплаты остались на стороне агентства. Когда двое заболели, замену прислали в тот же день.' },
{ co: 'Торговый дом «Ветка»', kind: 'exec', field: 'Оптовые продажи продуктов питания',
roles: ['Коммерческий директор'], people: 1, days: 38, who: 'Сергей Мальцев, собственник',
txt: 'Позиция закрытая, объявление размещать было нельзя. Агентство собрало карту рынка по нашей нише и вышло на действующих руководителей. Кандидат работает второй год, оборот направления за это время вырос на 41 процент.' },
{ co: 'Клиника «Сфера здоровья»', kind: 'spot', field: 'Медицинские услуги, две клиники',
roles: ['Администратор', 'Врач-терапевт', 'Медицинская сестра'], people: 7, days: 19, who: 'Ольга Тимченко, главный врач',
txt: 'Ценю, что кандидатов проверяли по документам и сертификатам до собеседования: мы не тратили время на тех, у кого не в порядке аккредитация. Отдельный плюс за обратную связь тем, кто нам не подошёл.' },
{ co: 'Строительная компания «Вектор-С»', kind: 'mass', field: 'Малоэтажное строительство',
roles: ['Монтажник', 'Разнорабочий', 'Прораб'], people: 18, days: 31, who: 'Дмитрий Крылов, руководитель проектов',
txt: 'Работали по трём объектам одновременно, люди нужны были в разных районах области. Агентство разделило поиск по площадкам и закрыло бригады к началу сезона. Двоих меняли по гарантии, вопросов по срокам замены не было.' }
];
var roots = document.querySelectorAll('.vbor');
for (var i = 0; i < roots.length; i++) init(roots[i]);
function init(root) {
if (root.__vb) return; root.__vb = 1;
var grid = root.querySelector('#vbor-grid'), bar = root.querySelector('#vbor-filter');
var cnt = root.querySelector('#vbor-count'), sum = root.querySelector('#vbor-sum');
var cur = 'all';
function plural(n, a) { var m = n % 100; if (m > 4 && m < 21) return a[2]; m = n % 10; return m === 1 ? a[0] : (m > 1 && m < 5 ? a[1] : a[2]); }
var people = 0, days = 0, j;
for (j = 0; j < REVIEWS.length; j++) { people += REVIEWS[j].people; days += REVIEWS[j].days; }
sum.innerHTML = '<li><b>' + people + '<\/b><span>человек вышло на работу по этим заявкам<\/span><\/li>' +
'<li><b>' + Math.round(days / REVIEWS.length) + '<\/b><span>дней средний срок закрытия заявки<\/span><\/li>';
bar.innerHTML = TABS.map(function (t) {
return '<button type="button" class="vbor-chip" data-k="' + t.k + '" aria-pressed="' + (t.k === 'all') + '">' + t.n + '<\/button>';
}).join('');
function draw() {
var list = [];
for (var i = 0; i < REVIEWS.length; i++) if (cur === 'all' || REVIEWS[i].kind === cur) list.push(REVIEWS[i]);
grid.innerHTML = list.map(function (r, i) {
return '<article class="vbor-card" style="animation-delay:' + (i * 60) + 'ms"><div class="vbor-card__top">' +
'<span class="vbor-mark">' + r.co.replace(/[^А-Яа-яA-Za-z]/g, '').charAt(0) + '<\/span>' +
'<span><b class="vbor-co">' + r.co + '<\/b><span class="vbor-field">' + r.field + '<\/span><\/span><\/div>' +
'<ul class="vbor-roles">' + r.roles.map(function (x) { return '<li>' + x + '<\/li>'; }).join('') + '<\/ul>' +
'<p>' + r.txt + '<\/p>' +
'<div class="vbor-facts"><div><b>' + r.roles.length + '<\/b><span>' + plural(r.roles.length, ['позиция', 'позиции', 'позиций']) + ' в заявке<\/span><\/div>' +
'<div><b>' + r.people + '<\/b><span>' + plural(r.people, ['человек вышел', 'человека вышло', 'человек вышло']) + '<\/span><\/div>' +
'<div><b>' + r.days + '<\/b><span>' + plural(r.days, ['день на подбор', 'дня на подбор', 'дней на подбор']) + '<\/span><\/div><\/div>' +
'<span class="vbor-who">' + r.who + '<\/span><\/article>';
}).join('');
cnt.textContent = 'Показано ' + list.length + ' ' + plural(list.length, ['отзыв', 'отзыва', 'отзывов']) + ' из ' + REVIEWS.length;
}
bar.addEventListener('click', function (e) {
var b = e.target.closest ? e.target.closest('.vbor-chip') : null;
if (!b) return;
cur = b.getAttribute('data-k');
var bs = bar.querySelectorAll('.vbor-chip');
for (var i = 0; i < bs.length; i++) bs[i].setAttribute('aria-pressed', bs[i].getAttribute('data-k') === cur ? 'true' : 'false');
draw();
});
draw();
}
})();
</script> Вставляется целиком в блок T123 «HTML-код». Внутри уже есть стили и скрипт, подключать ничего не нужно.
Как вставить блок в Tilda
- Скопируйте кодКнопка «Скопировать код» выше кладёт всё содержимое в буфер обмена.
- Добавьте блок T123В редакторе страницы: «Библиотека блоков» → «Другое» → T123 «HTML-код».
- Вставьте и сохранитеНажмите «Контент», вставьте код в поле, сохраните и обновите страницу.
- ОпубликуйтеВ превью скрипты Tilda работают не всегда — проверяйте на опубликованной странице.
Подробная инструкция с граблями — как вставить вайб-блок в Tilda.
Что менять под себя
| Где в коде | За что отвечает |
|---|---|
REVIEWS в начале скрипта | компания, сфера, позиции, число людей, срок и текст отзыва |
TABS в начале скрипта | названия форматов услуги для фильтра над лентой |
поле who в каждом отзыве | имя и должность человека, который дал отзыв |
--acc в начале стилей | цвет активного чипа, сводных цифр и буквы вместо логотипа |
Отзывы работодателей: зачем он нужен
Отзыв работодателя убеждает цифрами по заявке, а не общими словами. Каждая плитка показывает компанию, её сферу, перечень закрытых позиций, число вышедших людей, срок подбора и должность автора отзыва. Над лентой стоят две сводные цифры: сколько человек вышло на работу по всем заявкам и какой средний срок закрытия. Обе считаются из массива отзывов, поэтому при добавлении новой записи их править не нужно.
Чипы над лентой фильтруют отзывы по формату услуги: массовый подбор, специалисты, руководители и аутстаффинг. При переключении карточки перерисовываются с короткой анимацией появления, а под лентой обновляется строка с числом показанных отзывов. Склонение слов вроде дня, дней и позиций считает отдельная функция, поэтому цифры читаются естественно при любых значениях. Фотографий в блоке нет, вместо логотипа стоит первая буква названия компании.
Вопросы по этому блоку
-
Допишите объект в массив REVIEWS с полями co, kind, field, roles, people, days, who и txt. Ключ kind должен совпадать с одним из ключей в массиве TABS, иначе отзыв покажется только в общем списке.
-
Оставьте в массиве TABS один объект с ключом all, тогда над лентой будет одна кнопка. Можно скрыть контейнер фильтра стилем display none, логика вывода отзывов при этом сохранится.
-
Скрипт складывает поля people всех отзывов и усредняет поля days. Если нужны другие показатели, поправьте сборку строки sum в начале функции инициализации.
-
Да. Код на этой странице копируется целиком, без регистрации и подписки. Указывать авторство не нужно, использовать можно в коммерческих проектах.
-
Нет. Все классы внутри имеют собственный префикс vbor, поэтому не пересекаются ни со стилями Tilda, ни с другими блоками. Скрипт привязан к своему элементу и запускается один раз, даже если блок вставлен дважды.
-
Раскладка перестраивается под узкие экраны, размеры заданы через clamp, поля ввода имеют шрифт 16 пикселей — iOS не будет зумить страницу при фокусе. Отдельной мобильной версии подключать не нужно.
Другие блоки отзывов
Ещё блоки для подбора персонала
Собрать сайт целиком
Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса. Как это выглядит для ниши «Подбор персонала», видно на отдельной странице.