Картковий інтерфейс і візуальні блоки
1) Навіщо картки
Картки упаковують сутність (гра, матч, акція, стаття) з ключовими атрибутами і діями. Хороша картка:- швидко сканується,
- дає один головний CTA,
- адаптується до різних контейнерів/колонок,
- передбачувана по поведінці (hover, press, фокус, контекстне меню).
2) Анатомія картки
Мінімальний склад:1. Медіа-зона (обкладинка/логотип/прев'ю, 16:9/4:3/1:1).
2. Заголовок (1-2 рядки з усіченням).
3. Метадані (підзаголовок, тег/категорія, провайдер, час).
4. Бейджі статусу (новинка, live, акція, рейтинг).
5. СТА/швидкі дії (кнопка або іконки).
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.