Готовые блоки

Четырнадцать крупных сегментов вёрстки, которые забирают в проект целиком: шапка, первый экран, сетка карточек, карточка товара, тарифы, форма входа, лента статей, панель админки, дашборд, таблица с фильтрами, вопросы и ответы, призыв к действию, подвал и каталог с фасетами. У каждого — вкладка «Код» и кнопка копирования.

14 сегментов только классы библиотеки ни одного литерального цвета в оформлении

Как этим пользоваться

Каждый блок ниже собран только на классах библиотеки: ни одного литерального цвета, ни одного пикселя в разметке, ни строчки собственного CSS у этой страницы. Единственный атрибут style на всей странице — оценка товара в --gr-rating: это данные, а не оформление. Поэтому блок, перенесённый в ваш проект, сразу знает про светлую и тёмную тему, про режим для слабовидящих и про выбранную стратегию оформления — переключатели в боковой панели действуют и на эти сегменты, попробуйте.

Порядок работы: вкладка «Код»«Копировать» → вставить в свою разметку → заменить тексты и ссылки. Классы gr-area-* в панели админки и data-gr-layout на её контейнере — единственное место, где нужен JS-рантайм библиотеки; остальные тринадцать блоков работают без него. Своего кода просит один счётчик количества в карточке товара — два вызова stepUp() / stepDown() прямо в разметке блока.

Что нужно подключить. Все блоки требуют трёх файлов: griffincss-core.css, griffincss-ui.css и griffincss-utils.css. Панели админки нужен ещё griffincss.js. Ни одна картинка, иконка или шрифт в комплект не входят: в блоках стоят заглушки на фоновых утилитах и юникодные символы — замените их на своё.

1. Шапка сайта

Бренд, меню и действие. До 768px меню сворачивается в кнопку — это <details>, без единой строки JS.

Шапка целиком — сузьте окно, чтобы увидеть кнопку меню
Астролябия
Войти

2. Первый экран

Заголовок, одна фраза о продукте, два действия и строка доверия. Ширина текста ограничена gr-max-w-page, а не пикселями, поэтому на широком мониторе строка не растягивается до нечитаемой.

Первый экран
Версия 2.0 уже здесь

Сетка, которая описывается одной строкой

Опишите раскладку строкой a3b4-c2d5 вместо десяти правил grid-template-areas. Адаптивность — атрибутом, без единого медиа-запроса вручную.

Без карты · 14 дней · Отмена в один клик

3. Сетка карточек

gr-grid-auto-fit сама решает, сколько колонок поместится: ни одного брейкпоинта в разметке. Карточки выравниваются по нижнему краю, потому что подвал прижат gr-card-footer, а не отступом.

Три карточки, которые сами перестроятся в одну колонку
изображение

Каскадные слои

Библиотека укладывается в свой @layer, поэтому ваши правила побеждают без !important.

изображение

Две оси темы

Светлая и тёмная — одна ось, режим для слабовидящих — вторая, независимая от первой.

изображение

Контейнерные запросы

Те же брейкпоинты, но от ширины блока: карточка в узкой колонке ведёт себя как на телефоне.

4. Карточка товара

Витрина магазина целиком: стикеры поверх обложки, рейтинг-звёзды, цена со старой ценой и размером скидки, выбор цвета и размера, счётчик количества и кнопка. Нового CSS здесь два модуля — gr-rating: дробное заполнение знака из готовых утилит не собирается, — и образцы gr-swatch / gr-swatch-tag: радио в виде кружка цвета и плашки размера, где состояние «выбран» на самом образце ни одна утилита дать не могла. Всё остальное уже было — gr-badge в углу gr-relative-обёртки, gr-line-through на старой цене, gr-input-group вокруг пары кнопок со счётчиком.

Под курсором карточка приподнимается — это gr-hover-lift из модуля трансформаций, один класс со своим переходом и своим @media (hover: hover) внутри. На сенсорном экране эффект не залипает после касания, а при prefers-reduced-motion: reduce сжимается до неразличимого. Ни своего @media, ни своего transition в блоке для этого не появилось.

Стикер стоит на логическом gr-start-0 — физической привязки в библиотеке больше нет: под dir="rtl" он уезжает к правому краю обложки сам. Оценка дублируется числом рядом и aria-label на самом рейтинге — пять знаков это цвет и форма, а они не переживают ни печать, ни программу чтения с экрана. Кнопка «В корзину» прижата к низу тем же приёмом, что подвал карточки в третьем блоке: gr-flex-1 на строке цены забирает остаток высоты, и кнопки в ряду встают на одну линию.

style на всей странице есть только здесь. В нём данные товара: значение оценки --gr-rating: 4.5 и цвет образца --gr-swatch: #1f1f1f. Это данные, а не оформление — кегль, размеры и раскладка по-прежнему целиком на классах, и в библиотеке от цвета товара не остаётся ни одного литерала. Второе исключение рядом: кнопки счётчика зовут stepDown() и stepUp() у соседнего поля прямо из разметки — счётчик в демонстрации рабочий, и скопированный блок работает так же. Методы родные, они уважают min, max и step, а системные стрелки у поля снимает gr-input-no-spin — рядом с кнопками они второй орган управления тем же числом. Всё остальное — погасить «минус» на границе, послать change в пересчёт корзины — остаётся за вашим кодом, см. формы.

Витрина: стикер, рейтинг, цена, счётчик
изображение
−25 % Хит

Рюкзак «Каппадокия», 22 л

4,5 · 64 отзыва
Цвет

12 990 ₽ Старая цена 17 320 ₽

изображение
Новинка

Термокружка «Полдень», 0,4 л

5,0 · 9 отзывов

2 450 ₽

изображение
Нет в наличии

Плед «Хвоя»

3,2 · 5 отзывов
Размер

4 100 ₽

Сообщим, когда появится.

5. Тарифы

Три плана, средний выделен рамкой и плашкой, а не размером: увеличенная карточка ломает выравнивание цен, и глаз перестаёт их сравнивать.

Три тарифа, средний выделен

Свободный

Для личных проектов

0 ₽

навсегда

  • Все модули библиотеки
  • Одна тема
  • Сообщество
Рабочий Выбирают чаще

Рабочий

Для команды до десяти человек

1 490 ₽

в месяц

  • Всё из «Свободного»
  • Обе оси темы и стратегии оформления
  • Поддержка за один рабочий день

Корпоративный

Для крупных внедрений

Договорная

по итогам разговора

  • Всё из «Рабочего»
  • Свои токены и сборка
  • Договор и SLA

6. Форма входа

Каждое поле — gr-field с подписью и подсказкой, связанной через aria-describedby. Ошибка показана словом, а не только цветом рамки. У пароля — кнопка «Показать» в .gr-input-group: три строки на странице переключают type, aria-pressed и подпись, виджета для этого нет.

Карточка входа

Вход

Ещё нет учётной записи? Зарегистрируйтесь.

Та, на которую оформлена подписка.
Пароль короче восьми знаков.

7. Лента статей

Крупная статья и две поменьше. Раскладка описана строкой gr-grid-12 со span-утилитами, поэтому на узком экране колонки схлопываются сами.

Витрина блога
обложка
Архитектура 12 минут чтения

Почему каскадные слои важнее специфичности

Спор о том, какое правило победит, решается не подсчётом единиц специфичности, а порядком слоёв — и это меняет способ писать библиотеки целиком.

8. Панель админки

Единственный блок на этой странице, которому нужен griffincss.js: раскладка описана строкой data-gr-layout, а на широком экране меняется на data-gr-layout-md — без единого медиа-запроса в разметке.

Каркас административной панели
Панель МЛ

Сводка за неделю

Отчёт готовится Данные за последние сутки появятся к полуночи.

9. Дашборд со статистикой

Четыре показателя в ряд, под ними — полосы выполнения. Числа набраны gr-font-mono: в колонке показаний разряды обязаны стоять друг под другом, а пропорциональный шрифт этого не обещает. Полоса — родной <progress>, а не div со вложенным span: доступность у него уже есть.

Показания и прогресс

Выручка

1 284 900 ₽

↑ 12,4% к прошлой неделе

Заказы

438

↑ 3,1%

Средний чек

2 934 ₽

↓ 1,8%

Возвраты

7

без изменений

План квартала
Выручка78%
78 %
Новые клиенты45%
45 %
Удержание23%
23 %

10. Таблица с фильтрами

Панель отбора, таблица в прокручиваемой обёртке и страницы под ней. gr-table-wrap с tabindex="0" — чтобы до прокрутки можно было добраться с клавиатуры; ниже 640 px прокрутка не понадобится — .gr-table-stack-sm складывает каждую строку в карточку с подписями из data-label («Карточки вместо строк»). Период — пара нативных полей даты, сумма — текстовое поле: без скрипта оба работают как есть, с подключённым griffinjs-fields.js поля периода связываются атрибутом to (второе не раньше первого), а сумма получает разряды по локали — «С подключённым griffinjs-fields.js».

Список заказов период и сумма — нужен griffinjs-fields.js
НомерКлиентСтатусСумма
A-10482Кузнецова А.Оплачен12 400 ₽
A-10481Орлов Д.В сборке3 950 ₽
A-10480Гаврилова Е.Отменён7 100 ₽
A-10479Северов И.Оплачен21 800 ₽

Показаны 1–4 из 96

11. Вопросы и ответы

Аккордеон на <details name="…">: общее имя заставляет браузер закрывать соседей сам, без JS и без управления состоянием.

Частые вопросы
Нужен ли JS, чтобы пользоваться библиотекой?

Нет. Без JS работают все утилитарные классы, все компоненты и статические SCSS-миксины раскладок. Рантайм нужен только для data-gr-layout, тем и произвольных значений в квадратных скобках.

Можно ли подключить только часть?

Да, пакета три, и каждый самодостаточен. Минимальный набор — griffincss-core.css в 24 КБ; утилиты и компоненты добавляются по желанию.

Что будет с моими стилями?

Ничего. Весь вывод библиотеки лежит в каскадных слоях griffincss.*, а безслойные правила побеждают любой слой. Ни одного !important в сборке нет — это проверяется на каждой сборке.

Как быть с тёмной темой?

Она уже есть. Цвета компонентов заданы семантическими токенами, поэтому обе темы и режим для слабовидящих приходят к вашей вёрстке даром — если вы пользуетесь классами, а не литеральными цветами.

12. Призыв к действию

Полоса на цвете акцента. Текст берёт gr-text-on-accent, а не белый: в режиме для слабовидящих пара «фон — текст» меняется вместе, и контраст сохраняется.

Полоса действия

Попробуйте на своём проекте

Три файла, ноль зависимостей, четырнадцать дней без карты.

13. Подвал сайта

Четыре колонки на широком экране, две на планшете, одна на телефоне — gr-grid-1 gr-grid-2-sm gr-grid-4-lg, три класса вместо двух медиа-запросов. Здесь колонки заданы числом, а не gr-grid-auto-fit: у подвала их ровно четыре по смыслу, и отдавать это решение ширине экрана незачем. Нижняя строка отделена границей, а не отступом: так видно, где кончается навигация и начинается правовая часть.

Подвал

14. Каталог с фасетами

Боковая колонка отбора (четыре доли из двенадцати) и сетка карточек — gr-grid-12-lg со span-утилитами; ниже 1024 px колонки схлопываются в одну. Порог здесь lg, а не md: на планшете три колонки из двенадцати оставляют фасетам полосу, в которую не помещается ни цена «от — до», ни подпись флажка. Весь сегмент лежит внутри одной <form method="get">: отбор уезжает в адресную строку, страница возвращается с теми же значениями в полях, и переносится это в любой движок сайта как есть. Ни одной строки скрипта, ни одного нового класса.

Цена — два числовых поля «от» и «до», и это база: без скрипта форма работает ими. С подключённым griffinjs.js над полями ложится пара ползунков с параметром fields на обёртке — потянул ручку, число обновилось; вписал число, ручка уехала. Отправляют форму по-прежнему поля: name у них, у ползунков его нет, и в адрес уезжают два параметра, а не четыре.

Фасеты — вложенные <details>: группа сворачивается, и это платформа, а не виджет. Внешний <details open> «Фильтры» нужен телефону: там колонка идёт над товаром, и её сворачивают одним касанием. Выдвижной панели здесь намеренно нет — она потребовала бы второго набора тех же полей в форме (или своего CSS у этой страницы), а дубль полей в GET-форме отправляет фасет дважды.

Чего здесь нет и не будет: счётчиков у фасетов, логики фильтрации и состояния в адресе, собираемого скриптом. Это витрина, а не приложение: разметка и форма — всё. Крестик у выбранного фасета — ссылка на тот же адрес без этого параметра, а не кнопка, которой нужен обработчик.

Каталог: фасеты, чипы выбранного, сортировка ползунок цены — нужен griffinjs.js
Выбрано: Ноутбуки × Asus ×
изображение

Asus ProArt 16

16", 32 ГБ, 1 ТБ

184 900 ₽

Чего здесь нет

Ни выбора даты, ни фильтрации по щелчку. Это не забывчивость: таким блокам нужен не «тонкий опциональный JS», а полноценный виджет с управлением состоянием — другая ответственность и другой размер. Всё, что на этой странице, работает от разметки и стилей, и ровно один сегмент из четырнадцати просит рантайм.

Фасетный фильтр из этого списка ушёл — но ушла только его разметка: сегмент 14 отбирает <form method="get">, а счётчики у фасетов, подгрузка выдачи и состояние в адресе остаются за приложением. Граница та же, что и была: витрина показывает, приложение считает.

Автодополнение и сортировка таблицы стояли здесь же — и оба уже неправда: комбобокс и сортируемая таблица приехали тем же опциональным слоем. У сортировки основание пересмотра названо отдельно: перестановка строк по признаку из разметки обходится без модели состояния, а выбор даты — нет, и он в списке остался.

Про карусель здесь раньше стояло то же самое, и это уже неправда: слайдер, галерея, лайтбокс, параллакс и мегаменю приехали опциональным слоем griffinjs.js внутри пакета griffincss-ui — «другая библиотека» получила имя и место, не меняя состава npm. Подключается она отдельным файлом и по-прежнему никому не навязывается: все четырнадцать блоков выше собраны без неё. Единственное место, где она подключена, — ползунок цены в каталоге с фасетами, и он лежит поверх двух числовых полей, которые работают и без него.

Товарной специфики здесь тоже нет как отдельного API: в карточке товара ни gr-price, ни gr-sticker, ни gr-qty — цена собирается кеглем и gr-line-through, стикер это gr-badge в углу, счётчик — gr-input-group. Своим классом стал только рейтинг: дробное заполнение знака из готовых утилит не собирается, а остальное собирается — и тогда новое имя не добавляет ни одного свойства.