GH GambleHub

Карточный интерфейс и визуальные блоки

1) Зачем карточки

Карточки упаковывают сущность (игра, матч, акция, статья) с ключевыми атрибутами и действиями. Хорошая карточка:
  • быстро сканируется,
  • дает один главный CTA,
  • адаптируется к разным контейнерам/колонкам,
  • предсказуема по поведению (hover, press, фокус, контекстное меню).

2) Анатомия карточки

Минимальный состав:

1. Медиа-зона (обложка/логотип/превью, 16:9/4:3/1:1).

2. Заголовок (1–2 строки с усечением).

3. Метаданные (подзаголовок, тег/категория, провайдер, время).

4. Бейджи статуса (новинка, live, акция, рейтинг).

5. CTA/быстрые действия (кнопка или иконки).

6. Вторичный текст (короткий, 2–3 строки max).

7. Контролы (избранное, … контекст).

Иерархия: медиа → заголовок → CTA → мета → вторичное. Деструктивные действия скрыты или вынесены в меню.

3) Сетки и раскладки

Grid (фиксированный столбец): 2–6 колонок; адаптив через auto-fit/auto-fill.
Responsive tiles: `minmax(240px, 1fr)` — карточки растут ровно до границ.
Masonry/варьирующаяся высота: осторожно; обеспечить порядок фокуса и читабельность.
List (в ряд): когда важна горизонтальная экономия и сортируемость.

css
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px,1fr));
gap: 16px;
}
.card {
border-radius: 12px;
background: var(--bg-elevated);
box-shadow: var(--elev-2);
display: grid;
grid-template-rows: auto 1fr auto;
overflow: hidden;
}
.card__media { aspect-ratio: 16/9; object-fit: cover; }

4) Плотность и ритм

Поля/отступы: внутри 12–16 px; между блоками 8–12 px.
Высота строки: 1.3–1.5; шрифты: заголовок 16–18 px, мета 12–14 px.
Клиппинг текста: `line-clamp: 2–3`; обязательно полный текст в tooltip/деталях.

5) Состояния и интерактивность

Hover/Focus/Active: тень/подсветка, но без «скачков» макета; `:focus-visible` всегда видим.
Selectable: чекбокс/рамка; не путать со ссылочной карточкой.
Pressed: уменьшение до 98% + тень вниз (≤ 120 мс).
Busy/Loading: скелетон, а не «пусто».

css
.card:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.card:hover { box-shadow: var(--elev-3); transform: translateY(-1px); transition: box-shadow. 16s, transform. 16s; }

6) Изображения и медиа

Aspect-ratio жестко фиксирован; на списках игр — 16:9 или 4:3.
Ленивая загрузка: `loading="lazy"` + `decoding="async"`.
Плейсхолдер/скелетон с доминирующим цветом постера.
Ошибка загрузки: подставная картинка + иконка «image-off».

html
<img class = "card __ media" src ="..." alt = "Game name" loading =" lazy" onerror =" this. src='/fallback. png'">

7) Бейджи и метки

Короткие (1–2 слова): New, Live, -20%, Top 10.
Нельзя полагаться только на цвет — добавляйте иконку/текст.
Расположение: левый верх медиа; несколько — в стеке с зазором 4–6 px.

css
.badge { display:inline-flex; gap:6px; align-items:center; padding:4px 8px; border-radius:8px; font-size:.75rem; }
.badge--live { background: var(--bg-danger); color: var(--on-danger); }

8) CTA и быстрые действия

Один primary на карточку (например, «Играть», «Сделать ставку»).
Вспомогательные иконки (избранное, поделиться, …) — по hover/фокусу.
Деструктивные — через подтверждение или undo-панель.

html
<div class="card__actions">
<button class="btn btn--primary">Играть</button>
<button class =" icon" aria-label = "Add to Favorites" title =" B Favorites "> </button>
<button class="icon" aria-haspopup="menu" aria-expanded="false">⋯</button>
</div>

9) Доступность (A11y)

Вся карточка-ссылка — `<a>` с понятным `aria-label`, иначе: заголовок как ссылка, остальное — статично.
Порядок Tab соответствует визуальному; фокус-кольцо видно.
Изображения с `alt`; декоративные — `aria-hidden="true"`.
Для статусов используйте `role="status"`/`aria-live="polite"`.
Контраст текста и бейджей ≥ AA; смысл не только цветом.

10) Перформанс

Ленивая загрузка медиа и списков; пагинация или инфинит-скролл с sentry-наблюдателем.
Виртуализация для ленточных/бесконечных выдач (±10k элементов).
Минимизируйте reflow: анимируйте только `transform/opacity`.
Рендерите карточки скелетонами и заменяйте контентом после загрузки данных.

11) Скелетоны, ошибки, пустые

Скелетон повторяет структуру карточки (медиа/текст/кнопка), без агрессивного shimmer; учитывайте `prefers-reduced-motion`.
Error-state: иконка + краткий текст («Не удалось загрузить игру») + кнопка Retry.
Empty-state: иконка/иллюстрация, пояснение, «Что дальше» (фильтр/поиск/подписки).

12) Управление контентом

Усечение: `line-clamp` + явные подсказки (tooltip).
Длинные числа/суммы: табличные цифры: `font-variant-numeric: tabular-nums;`.
Локализация: резерв +20–30% ширины для длинных лейблов.
RTL-поддержка: флип бейджей/иконок и выравнивания.

13) Темная тема и контраст

Тени слабее, используйте границы (`1px`) с прозрачностью.
Поддерживайте AAA для малых шрифтов; избегайте мерцаний.
Медиа затемняются тонкой вуалью (overlay 8–12%), чтобы текст читался.

css
.theme-dark. card { background: var(--bg-elevated-dark); box-shadow: var(--elev-1-dark); }
.theme-dark. card__media::after { content:""; position:absolute; inset:0; background: rgba(0,0,0,.12); }

14) Сортировка, фильтры, пагинация

Панель фильтров сверху/сбоку; результат — сетка карточек.
Пагинация видима; бесконечный скролл — только с «Назад к началу» и сохранением позиции.
Фильтры не «сбрасывают» скролл; применяются быстро (≤ 100 мс) или с индикатором.

15) Специфика iGaming

15.1 Карточка игры (slot/table)

Медиа: постер 16:9, логотип провайдера.
Метаданные: провайдер, RTP, волатильность, категории (— только информативно, без обещаний выигрыша).
Бейджи: New, Popular, Tournament, Jackpot.
CTA: «Играть» + «Демо». Контекст «18+» и ответственная игра — видимы.

15.2 Карточка матча/коэффициента

Живой бейдж Live; таймер/период.
Ключевые коэффициенты (2–3) с мгновенным hover/press и безопасным undo (если допущено).
Обновления без мерцаний; при изменении курса — аккуратная подсветка.

15.3 Карточка турнира/ивента

Даты, призовой фонд, правила (ссылка).
Статус («Регистрация открыта/закрыта», «Идет»).
CTA «Присоединиться», «Правила»; прогресс участия (очки/место).

16) Антипаттерны

Вся карточка кликабельна + внутри вторичные ссылки (ловушки фокуса/кликов).
Два primary-CTA рядом («Играть» и «Купить бонус») — конкуренция внимания.
Отсутствие плейсхолдеров/скелетонов → «прыгающая» сетка (CLS).
Бесконечные shimmer-эффекты; анимация тенью/blur (дорого).
Метаданные «в столбик» мелким серым на сером (нет контраста).
Бейджи, передающие смысл только цветом.

17) Токены дизайн-системы (пример)

json
{
"card": {
"radius": 12,
"gap": 12,
"mediaRatio": "16/9",
"px": "12 12 12 12",
"shadow": { "rest": "var(--elev-2)", "hover": "var(--elev-3)" }
},
"badge": { "radius": 8, "px": "4 8", "icon": 14 },
"grid": { "gap": 16, "min": 240, "max": 1 },
"motion": { "hoverMs": 160, "pressMs": 100, "fadeMs": 160 },
"a11y": { "contrastAA": true, "focusRingWidth": 2, "focusRingOffset": 2 }
}

18) Сниппеты

React: универсальная карточка

tsx type CardProps = {
title: string;
subtitle?: string;
mediaUrl?: string;
badges?: string[];
onPrimary?: () => void;
primaryLabel?: string;
onFav?: () => void;
children?: React. ReactNode;
};
export default function Card({
title, subtitle, mediaUrl, badges=[], onPrimary, primaryLabel='Открыть', onFav, children
}: CardProps){
return (
<article className="card group focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2">
<div className="relative">
{mediaUrl? <img className="w-full aspect-[16/9] object-cover" src={mediaUrl} alt={title}/>: <div className="aspect-[16/9] bg-neutral-200"/>}
<div className="absolute top-2 left-2 flex gap-1">
{badges. map(b => <span key={b} className="badge">{b}</span>)}
</div>
</div>
<div className="p-3 grid gap-2">
<h3 className="text-sm font-semibold line-clamp-2" title={title}>{title}</h3>
{subtitle && <p className="text-xs text-neutral-500 line-clamp-2">{subtitle}</p>}
{children}
<div className="flex items-center gap-8">
{onPrimary && <button className="btn btn--primary" onClick={onPrimary}>{primaryLabel}</button>}
{onFav && <button className="icon opacity-0 group-hover:opacity-100" aria-label="В избранное" onClick={onFav}></button>}
</div>
</div>
</article>
);
}

Инфинит-скролл sentry

js const sentry = document. querySelector('#sentry');
const io = new IntersectionObserver(entries=>{
if(entries. some(e=>e. isIntersecting)) loadMore();
}, { rootMargin: '200px' });
io. observe(sentry);

19) Метрики и эксперименты

CTR primary-CTA и Time-to-Click.
Scroll-depth → click: клики «над сгибом» / «под сгибом».
Карточка → просмотр деталей → конверсия.
Видимость бейджей и их влияние на CTR.
Skeleton visible time и CLS.
A/B: размер карточек, количество метаданных, видимость быстрых действий, тип сетки (list/grid).

20) QA-чек-лист

Доступность

  • Фокус-кольца видимы; порядок Tab логичен.
  • Alt-тексты и `aria-label` корректны; статус-бейджи с текстом.
  • Контраст текста/фона ≥ AA.

Поведение

  • Один primary-CTA; быстрые действия не перекрывают основной сценарий.
  • Hover/press/selected различимы; контекстное меню работает.
  • Пустые/ошибки/скелетоны корректны; есть Retry.

Перформанс

  • Ленивая загрузка медиа; нет резких скачков макета.
  • Виртуализация больших списков; анимации `transform/opacity`.

Сетка

  • `minmax(240px,1fr)` и `gap` адаптивны; Masonry не ломает фокус/порядок чтения.
  • RTL/локализация не «ломают» обрезку и бейджи.

21) Документация в дизайн-системе

Компоненты: `Card`, `GameCard`, `MatchCard`, `TournamentCard`, `StatusBadge`, `SkeletonCard`.
Токены: радиус/тени/отступы/слои, цвета бейджей, анимации.
Паттерны: «Один CTA», «Скелетон вместо спиннера», «Инфинит-скролл + сохранение позиции».
Do/Don’t-галерея: перегруженная карточка vs минимальная, «кликабельная вся карточка» vs явные элементы.

Краткое резюме

Карточки работают, когда у них есть четкая иерархия, один главный CTA, предсказуемые состояния, устойчивые сетки и уважение к перформансу и доступности. Зафиксируйте токены и паттерны, используйте скелетоны и ленивую загрузку, держите контент лаконичным — и карточные интерфейсы станут быстрыми, читабельными и конверсионными, особенно в сценариях iGaming.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Telegram
@Gamble_GC
Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.