283 lines
16 KiB
Markdown
283 lines
16 KiB
Markdown
# DESIGN.md
|
|
|
|
Портфолио-сайт продуктового дизайнера. Лонгриды кейсов, резюме, блог. Визуал — минимализм с акцентом на типографику и контент.
|
|
|
|
---
|
|
|
|
## Продукт
|
|
|
|
Одностраничный сайт-портфолио с внутренними страницами (кейсы, резюме, блог). Основной контент — лонгриды с описанием проектов. Навигация через главную страницу с секциями: навыки, портфолио, контакты.
|
|
|
|
**Характер:** Сдержанный, профессиональный. Без визуального шума. Контент — главный элемент интерфейса.
|
|
|
|
---
|
|
|
|
## Цвета
|
|
|
|
### Токены темы
|
|
|
|
| Токен | Назначение |
|
|
|---|---|
|
|
| `--theme-h` | Оттенок акцента (0–360°) |
|
|
| `--theme-s` | Насыщенность акцента |
|
|
| `--theme-l` | Светлота акцента |
|
|
| `--accent` | Основной акцентный цвет |
|
|
| `--accent-text` | Цвет текста на акцентном фоне |
|
|
| `--accent-soft` | Мягкий акцент для фона |
|
|
| `--bg` | Фон страницы |
|
|
| `--bg-elevated` | Поверхность второго уровня |
|
|
| `--surface` | Фон карточек и секций |
|
|
| `--text` | Основной текст |
|
|
| `--text-muted` | Приглушённый текст |
|
|
| `--line` | Рамки и разделители |
|
|
|
|
### Правила
|
|
|
|
- Акцент меняется через `--theme-h/s/l` на `<html>`. Все производные пересчитываются автоматически.
|
|
- Светлая/тёмная тема — `data-theme="light|dark"` на `<html>`.
|
|
- Нейтральные фоны (`--bg`, `--surface`) слегка подмешивают оттенок акцента через `--neutral-accent-tint`.
|
|
- Не используйте хардкод hex-значений. Всегда обращайтесь к токенам.
|
|
|
|
---
|
|
|
|
## Типографика
|
|
|
|
### Семейства
|
|
|
|
| `data-font` | Стек | Назначение |
|
|
|---|---|---|
|
|
| `merriweather` | Merriweather + Alice | По умолчанию. Alice — проза, Merriweather — заголовки |
|
|
| `medeo` | Medeo Sans | Гротеск, интерфейс и проза |
|
|
| `mono` | Source Code Pro + PT Mono | Моноширинный |
|
|
|
|
### Шкала
|
|
|
|
| Класс | Размер | Вес | Назначение |
|
|
|---|---|---|---|
|
|
| `.hero__eyebrow` | `0.78rem` | 700 | Подзаголовок секции, ввод кейса. Uppercase, letter-spacing 0.14em |
|
|
| `.hero__title` | `clamp(3.1rem, 7.2vw, 4.85rem)` | 700 | H1 главной страницы |
|
|
| `.case-page__h1` | `clamp(2rem, 3.9vw, 2.9rem)` | 700 | H1 кейса / внутренней страницы |
|
|
| `.case-page__sub` | `clamp(1.5rem, 2vw, 1.65rem)` | 500 | Подзаголовок под H1 |
|
|
| `.section__title` | `clamp(0.95rem, 1.35vw, 1.1rem)` | 600 | Заголовки секций («Навыки», «Портфолио») |
|
|
| `.section__prose` | наследует | — | Основной текст абзацев |
|
|
| `h2` в `.case-article` | `clamp(1.5rem, 2vw, 1.65rem)` | 500 | Разделы лонгрида |
|
|
| `h3` в `.case-article` | наследует | — | Подразделы внутри H2 |
|
|
|
|
### Правила
|
|
|
|
- Заголовки используют `clamp()` — размер масштабируется от вьюпорта.
|
|
- Не задавайте `font-size` в пикселях. Используйте `rem` или `clamp()`.
|
|
- `line-height` для прозы: `1.55` (базовый), для заголовков: `1.2`.
|
|
- `max-width` текстовой колонки: `42rem` (`.section__prose`).
|
|
|
|
---
|
|
|
|
## Отступы и сетка
|
|
|
|
### Токены
|
|
|
|
| Токен | Значение | Назначение |
|
|
|---|---|---|
|
|
| `--space` | `clamp(1rem, 4vw, 2.75rem)` | Горизонтальные поля + safe-area |
|
|
| `--max` | `none` | Ширина контента = вьюпорт минус padding |
|
|
| `--radius-sm` | Зависит от `data-radius` | Малые скругления |
|
|
| `--radius-md` | Зависит от `data-radius` | Средние скругления |
|
|
| `--radius-card` | Зависит от `data-radius` | Карточки |
|
|
|
|
### Секции
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.section` | Вертикальные отступы через `clamp()` |
|
|
| `.section--tight` | Компактные отступы (кейсы, внутренние страницы) |
|
|
| `.section--surface` | Прозрачный фон (для mesh на главной) |
|
|
| `.section__inner` | Центрированная обёртка с `max-width: var(--max)` |
|
|
| `.case-article` | Контентная колонка лонгрида: `max-width: 48rem` |
|
|
|
|
### Брейкпоинты
|
|
|
|
| Ширина | Что меняется |
|
|
|---|---|
|
|
| `860px` | Hero → 2 колонки (`1.15fr 0.85fr`) |
|
|
| `760px` / `1180px` | Карусель портфолио: 1 → 2 → 3 карточки |
|
|
| `720px` | Сетка навыков → 2 колонки |
|
|
| `1024px` | Навыки: 6-колоночная мозаика |
|
|
| `560px` / `1024px` | Контакты → 2 → 4 колонки |
|
|
| `640px` | Wide-блоки схлопываются в ширину колонки |
|
|
|
|
### Правила
|
|
|
|
- Отдельной 12-колоночной сетки нет. Используйте CSS Grid внутри секций.
|
|
- Горизонтальные отступы — `--space` + `safe-area-inset`.
|
|
- Wide-блоки (`.case-media--wide`, `.case-callout`) шире колонки: `min(100vw - 2*padding, content + 8rem)`.
|
|
|
|
---
|
|
|
|
## Компоненты
|
|
|
|
### Кнопки
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.btn` | Базовый класс кнопки |
|
|
| `.btn--primary` | Основная кнопка (акцентный фон, стекло) |
|
|
| `.btn--secondary` | Вторичная кнопка (нейтральное стекло) |
|
|
| `.btn--ghost` | Текстовая кнопка без фона |
|
|
| `.btn--flat` | Плоский вариант (без «объёма») |
|
|
| `.btn--raised` | Приподнятый вариант (с тенью) |
|
|
| `.btn__icon` | Иконка внутри кнопки |
|
|
|
|
### FAB-кнопки
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.fab` | Базовый класс плавающей кнопки (круглая, `position: fixed`) |
|
|
| `.fab--primary` | Акцентная FAB (градиент, стекло, `--on-accent` для текста/иконки) |
|
|
| `.fab--secondary` | Вторичная FAB (нейтральная, для настроек) |
|
|
| `.fab--label` | Модификатор: снимает фиксированную ширину, добавляет текст рядом с иконкой |
|
|
| `.fab-primary__ico` | Иконка внутри primary FAB (маска через `mask-image`) |
|
|
| `.fab__label` | Текстовая подпись внутри FAB |
|
|
|
|
Правило: `--on-accent` вычисляется в синхронном `theme-init-script` (в `<head>`) по luminance акцента. Не задавайте `color` вручную — наследуется от `.fab--primary`.
|
|
|
|
### Теги
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.hero__tags` | Контейнер тегов в Hero |
|
|
| `.hero__tag` | Тег (пилл с рамкой). Используйте для ключевых слов |
|
|
| `.portfolio-card__tag` | Тег внутри карточки портфолио |
|
|
| `.mp-card__tags` | Контейнер тегов в mp-card |
|
|
| `.mp-card__tag` | Тег внутри mp-card |
|
|
|
|
### Фильтр-чипы
|
|
|
|
Переключаемая группа тегов над списком карточек. Нажатый чип оставляет только элементы с
|
|
совпадающим тегом, остальные скрываются.
|
|
|
|
| Класс / атрибут | Назначение |
|
|
|---|---|
|
|
| `.filter-chips` | Контейнер чипов (`<ul>`). Атрибут `data-filter-chips` включает поведение |
|
|
| `.filter-chip` | Кнопка-чип. Атрибут `data-filter-value` = тег, который она включает |
|
|
| `.filter-chip__count` | Счётчик совпадений. Проставляется скриптом автоматически |
|
|
| `data-filter-scope` | Селектор контейнера с фильтруемыми элементами. По умолчанию `document` |
|
|
| `data-filter-item` | Помечает фильтруемый элемент |
|
|
| `data-filter-tag` | Теги элемента через пробел. Несколько тегов работают как OR |
|
|
|
|
Правила:
|
|
|
|
- Состояние держится в `aria-pressed="true|false"`, а не в классе. Оформление выбранного
|
|
чипа — `[aria-pressed="true"]`, поэтому оно не зависит от `:focus` и не залипает после клика.
|
|
- Значение `all` (или пустое) показывает все элементы. Такой чип обычно первый.
|
|
- Скрытие через атрибут `hidden` + `[data-filter-item][hidden] { display: none }` — сетка
|
|
не оставляет дыр. Плавное затухание потребовало бы анимации высоты, а для фильтра
|
|
мгновенный отклик важнее.
|
|
- JS: `initFilterChips()` в `public/js/modules/ui/filter-chips.js`, подключён в `main.js`.
|
|
Счётчики и стартовое состояние берутся из разметки, модуль сам их заполняет.
|
|
- Помечайте элементы `hidden`, а не удаляйте — иначе фильтр ломает раскладку при возврате.
|
|
|
|
### Карточки
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.portfolio-card` | Карточка проекта в портфолио |
|
|
| `.portfolio-card__body` | Текстовая часть |
|
|
| `.portfolio-card__cover` | Обложка |
|
|
| `.skill-task-card` | Карточка навыка (задача + решения) |
|
|
| `.contact-card` | Контактная карточка (ссылка или действие) |
|
|
|
|
### Сетка проектов
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.project-grid` | Сетка карточек проекта: 1 колонка на мобильном, 2 от `680px`, 3 от `1120px`; адаптивные интервалы между карточками |
|
|
| `.project-grid > li` | Элемент списка без собственного оформления; внутри используется компонент карточки, например `.mp-card` |
|
|
|
|
### Блоки лонгрида
|
|
|
|
| Класс | Назначение |
|
|
|---|---|
|
|
| `.hero__eyebrow` | Подзаголовок перед H1 |
|
|
| `.case-page__h1` | Заголовок страницы |
|
|
| `.case-page__sub` | Подзаголовок |
|
|
| `.section__prose` | Абзац текста |
|
|
| `.section__title` | Заголовок секции |
|
|
| `.case-callout` | Акцентный блок (важная мысль) |
|
|
| `.case-media` | Обёртка для изображения/видео |
|
|
| `.case-media--natural` | Изображение в натуральном масштабе |
|
|
| `.case-media--content` | По ширине текстовой колонки |
|
|
| `.case-media--wide` | Шире колонки статьи |
|
|
| `.case-media-gallery--wide` | Шире колонки статьи (галерея) |
|
|
| `.case-media-slider` | Слайдер: одна картинка, стрелки и точки-пагинация |
|
|
|
|
---
|
|
|
|
## Поведение
|
|
|
|
### Изображения
|
|
|
|
- Формат: **WebP** для всех изображений.
|
|
- Видео: **WebM** (MP4 как fallback).
|
|
- Lazy loading: `loading="lazy"`, `decoding="async"`.
|
|
- Просмотр по клику: `data-image-viewer` на `<img>`.
|
|
- Заглушка при загрузке: `.is-img-loading` / `.has-img-loading`.
|
|
|
|
### Секции
|
|
|
|
- Порядок на странице кейса: `header-case` → `fab-stack` → `main.case-article` → `projects-section` → `contact-section` → `footer`.
|
|
- Порядок на внутренних страницах: `header-minimal` → `fab-stack-home-contact` → `main.section` → `footer`.
|
|
|
|
### Навигация
|
|
|
|
- Главная: горизонтальная навигация по секциям.
|
|
- Внутренние страницы: ссылка «на главную» в шапке.
|
|
- Плавающие кнопки (FAB): тема, контакты.
|
|
|
|
---
|
|
|
|
## Do's and Don'ts
|
|
|
|
### Do's
|
|
|
|
- Используйте токены цвета (`--accent`, `--text`, `--surface`), не хардкодьте.
|
|
- Используйте `clamp()` для типографики — не фиксированные px/rem.
|
|
- Используйте `.section__prose` для основного текста — он задаёт `max-width` и `color`.
|
|
- Используйте `.hero__eyebrow` для подзаголовков перед заголовками.
|
|
- Используйте WebP для изображений, WebM для видео.
|
|
- Для лонгридов внутри `.case-article` — заголовки `h2`/`h3` стилизуются автоматически.
|
|
|
|
### Don'ts
|
|
|
|
- Не создавайте новые классы для типографики, если есть готовые в таблице шкалы.
|
|
- Не используйте `font-size` в пикселях.
|
|
- Не смешивайте стили из разных `data-font` на одной странице.
|
|
- Не используйте `.hero__tag` для навыков в резюме — используйте `.skill-card` или простой список.
|
|
- Не создавайте wide-блоки без необходимости — они выходят за колонку и ломают ритм.
|
|
- Не используйте декоративные градиенты на функциональных поверхностях.
|
|
|
|
---
|
|
|
|
## Страницы
|
|
|
|
| Страница | Шаблон | Ключевые компоненты |
|
|
|---|---|---|
|
|
| Главная | `src/pages/index.html` | Hero, Skills, Projects, Contact |
|
|
| Кейс | `src/pages/cases/*.html` | `.case-article`, `.hero__eyebrow`, `.case-page__h1`, `.case-media` |
|
|
| Резюме | `src/pages/resume*.html` | `.doc`, `.profile-header`, `.meta-grid`, `.timeline`, `.skill-grid` |
|
|
| Design System | `src/pages/cases/design-system.html` | Живой каталог компонентов и токенов |
|
|
| Demo elements | `src/pages/cases/template-elements-demo.html` | Элементы лонгрида: медиа, галереи, видео, callout |
|
|
| Mini projects | `src/pages/cases/mini-projects-showcase.html` | Карточки активности (mp-card) |
|
|
|
|
---
|
|
|
|
## Файлы
|
|
|
|
| Файл | Назначение |
|
|
|---|---|
|
|
| `public/css/main.css` | Единый CSS: токены + все компоненты |
|
|
| `src/pages/cases/design-system.html` | Живой каталог токенов, типографики, кнопок, карточек |
|
|
| `src/pages/cases/template-elements-demo.html` | Элементы лонгрида: медиа, галереи, видео, callout |
|
|
| `src/pages/cases/mini-projects-showcase.html` | Карточки активности (mp-card) |
|
|
| `docs/case-page-blocks.md` | Инструкция по блокам лонгридов |
|
|
| `DESIGN.md` | Этот файл — описание для AI-агентов |
|