docs: добавить стайлгайд nextjs-style-guide в репозиторий
- Добавлена документация SLM-архитектуры, базовых правил и прикладных разделов - Добавлены разделы: стили, SVG-спрайты, шаблоны генерации, PostCSS, REST, Realtime - Удалены устаревшие файлы (спрайты, скрипты, стили из app/)
This commit is contained in:
176
ai/nextjs-style-guide/applied/styles/styles-setup.md
Normal file
176
ai/nextjs-style-guide/applied/styles/styles-setup.md
Normal file
@@ -0,0 +1,176 @@
|
||||
---
|
||||
title: Настройка стилей
|
||||
description: "Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили."
|
||||
keywords: [variables.css, media.css, global.css, shared/styles, токены, переменные, custom-media, breakpoints, подключение стилей, базовые стили, инициализация]
|
||||
---
|
||||
|
||||
# Настройка стилей
|
||||
|
||||
Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили.
|
||||
|
||||
## Требования
|
||||
|
||||
- Установлен PostCSS или любой другой pre/post-процессор с поддержкой `@custom-media`.
|
||||
|
||||
## Файлы
|
||||
|
||||
Состав глобальных стилей — три файла:
|
||||
|
||||
| Файл | Роль |
|
||||
|------|------|
|
||||
| `variables.css` | Токены проекта (цвета, отступы, радиусы) |
|
||||
| `media.css` | Custom media queries (брейкпоинты по ширине и высоте) |
|
||||
| `global.css` | Точка сборки глобальных стилей: через `@import` тянет все остальные глобалы, импортируется в приложение один раз |
|
||||
|
||||
Правила подключения:
|
||||
|
||||
- В приложение импортируется **только** `global.css`.
|
||||
- `variables.css` и будущие глобальные файлы (резеты, темы, типографика) подключаются в `global.css` через `@import`.
|
||||
- `media.css` **не импортируется** — ни в `global.css`, ни в компоненты, ни в точку инициализации. Его читает CSS-процессор на этапе сборки (см. [PostCSS](../postcss.md)).
|
||||
|
||||
## Корневой `font-size`
|
||||
|
||||
Базовая единица `rem` в проекте привязана к **16px**: корневой `font-size` не переопределяется. `html { font-size: ... }` писать запрещено — пользовательская настройка размера шрифта в браузере должна работать (a11y). Все `rem`-значения в `media.css` и других стилях трактуются как `1rem = 16px по умолчанию`.
|
||||
|
||||
Reset браузерных дефолтов (`box-sizing`, сброс `margin`, типографика) каноном не задаётся — каждый проект решает сам. Если заводится — подключается через `global.css`.
|
||||
|
||||
## Установка
|
||||
|
||||
### 1. Создать файлы
|
||||
|
||||
```bash
|
||||
mkdir -p src/shared/styles
|
||||
touch src/shared/styles/variables.css src/shared/styles/media.css src/shared/styles/global.css
|
||||
```
|
||||
|
||||
### 2. Заполнить `media.css`
|
||||
|
||||
Файл `src/shared/styles/media.css`. Стандартный набор брейкпоинтов проекта; редактировать только при согласованном изменении шкалы.
|
||||
|
||||
Единица — `rem` (реагирует на корневой `font-size`). Перевод исходит из дефолтного `html { font-size: 16px }`, т.е. `1rem = 16px`.
|
||||
|
||||
```css
|
||||
/* src/shared/styles/media.css */
|
||||
|
||||
/* Ширина — Mobile First (min-width), кроме --xs (max-width) */
|
||||
@custom-media --xs (max-width: 35.9375rem); /* 575px — до sm */
|
||||
@custom-media --sm (min-width: 36rem); /* 576px — телефон альбом / малый планшет */
|
||||
@custom-media --md (min-width: 48rem); /* 768px — планшет */
|
||||
@custom-media --lg (min-width: 62rem); /* 992px — малый десктоп */
|
||||
@custom-media --xl (min-width: 75rem); /* 1200px — десктоп */
|
||||
@custom-media --2xl (min-width: 88rem); /* 1408px — широкий десктоп */
|
||||
@custom-media --3xl (min-width: 120rem); /* 1920px — full HD+ */
|
||||
|
||||
/* Высота — min-height */
|
||||
@custom-media --h-xs (min-height: 41.6875rem); /* 667px — iPhone SE портрет */
|
||||
@custom-media --h-sm (min-height: 43.875rem); /* 702px */
|
||||
@custom-media --h-md (min-height: 50.625rem); /* 810px — iPad портрет */
|
||||
@custom-media --h-lg (min-height: 56.25rem); /* 900px */
|
||||
@custom-media --h-xl (min-height: 62.5rem); /* 1000px */
|
||||
@custom-media --h-2xl (min-height: 68.75rem); /* 1100px */
|
||||
@custom-media --h-3xl (min-height: 75rem); /* 1200px */
|
||||
```
|
||||
|
||||
Правила:
|
||||
|
||||
- только `@custom-media` на верхнем уровне;
|
||||
- имена короткие, по шкале (`--xs` … `--3xl`); высотные — с префиксом `--h-`;
|
||||
- единица — `rem`, не `em`/`px`; пиксельное значение указывается комментарием;
|
||||
- значения ширины — `min-width` (Mobile First), исключение `--xs` — `max-width` (блок «строго меньше `--sm`»);
|
||||
- значения высоты — `min-height`.
|
||||
|
||||
### 3. Заполнить `variables.css`
|
||||
|
||||
Файл `src/shared/styles/variables.css`. Набор токенов под проект расширяется по мере роста дизайн-системы.
|
||||
|
||||
```css
|
||||
/* src/shared/styles/variables.css */
|
||||
:root {
|
||||
/* Цвета */
|
||||
--color-primary: #3b82f6;
|
||||
--color-bg: #ffffff;
|
||||
--color-bg-hover: #f5f5f5;
|
||||
--color-text: #1a1a1a;
|
||||
|
||||
/* Отступы */
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
|
||||
/* Скругления */
|
||||
--radius-1: 4px;
|
||||
--radius-2: 8px;
|
||||
}
|
||||
```
|
||||
|
||||
Правила:
|
||||
|
||||
- все токены определяются в `:root` — без вложенных селекторов;
|
||||
- именование — `kebab-case` по ролям: `--color-*`, `--space-*`, `--radius-*`;
|
||||
- `px` — основная единица для пространственных токенов;
|
||||
- темы накладываются поверх через `[data-theme="..."] { ... }` — в отдельном файле темы или здесь же.
|
||||
|
||||
`variables.css` напрямую в приложение не импортируется — только через `global.css`.
|
||||
|
||||
### 4. Заполнить `global.css`
|
||||
|
||||
Файл `src/shared/styles/global.css`. Единственный глобальный файл, импортируемый в точку инициализации приложения. Внутри — `@import` остальных глобалов относительным путём.
|
||||
|
||||
```css
|
||||
/* src/shared/styles/global.css */
|
||||
@import './variables.css';
|
||||
|
||||
/* Сюда же подключаются будущие глобалы через @import:
|
||||
* @import './reset.css';
|
||||
* @import './typography.css';
|
||||
* @import './themes.css';
|
||||
* media.css НЕ импортируется — он работает через PostCSS.
|
||||
*/
|
||||
```
|
||||
|
||||
Правила:
|
||||
|
||||
- пути в `@import` — относительные (`./variables.css`), не через алиасы; нативный CSS `@import` не понимает tsconfig-paths;
|
||||
- `media.css` в `global.css` **не импортируется**;
|
||||
- собственные глобальные правила (`html { ... }`, `body { ... }`) писать **не здесь**, а в отдельных файлах рядом (`reset.css`, `typography.css`) и подключать через `@import`. `global.css` — только точка сборки;
|
||||
- порядок `@import` определяет порядок каскада: токены первыми, дальше резеты / темы / типографика.
|
||||
|
||||
### 5. Подключить `global.css` в layout
|
||||
|
||||
Импорт делается **один раз** — в корневом layout приложения:
|
||||
|
||||
```tsx
|
||||
// src/app/layout.tsx
|
||||
import 'shared/styles/global.css'
|
||||
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'App',
|
||||
description: '',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="ru">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
`variables.css` и `media.css` в layout **не импортируются напрямую** — только через `global.css` (variables) или через PostCSS на сборке (media).
|
||||
|
||||
## Проверка установки
|
||||
|
||||
- В `src/shared/styles/` присутствуют три файла: `variables.css`, `media.css`, `global.css`. В `src/app/` папки `styles/` нет.
|
||||
- В `src/app/layout.tsx` есть `import 'shared/styles/global.css'`. Импортов `variables.css` и `media.css` там нет.
|
||||
- В проекте **не появились** PostCSS-пакеты и `postcss.config.*` — этот раздел их не ставит.
|
||||
- `npm run build` завершается успешно.
|
||||
|
||||
## Дальше
|
||||
|
||||
- [PostCSS](../postcss.md) — подключить процессор, чтобы заработали `@media (--md)` и вложенность.
|
||||
- [Использование стилей](./styles-usage.md) — правила написания CSS в компонентах.
|
||||
- [SVG-спрайты](../svg-sprites/svg-sprites-setup.md) — стили иконок отдельно от глобальных.
|
||||
271
ai/nextjs-style-guide/applied/styles/styles-usage.md
Normal file
271
ai/nextjs-style-guide/applied/styles/styles-usage.md
Normal file
@@ -0,0 +1,271 @@
|
||||
---
|
||||
title: Использование стилей
|
||||
description: Как пишутся стили в проекте.
|
||||
---
|
||||
|
||||
# Использование стилей
|
||||
|
||||
Как пишутся стили в проекте.
|
||||
|
||||
## Общие правила
|
||||
|
||||
- Только **PostCSS** и **CSS Modules** для кастомной стилизации.
|
||||
- Подход **Mobile First** — стили пишутся от мобильных к десктопу.
|
||||
- Именование классов — `camelCase` (`.root`, `.buttonNext`, `.itemTitle`).
|
||||
- Корневой класс каждого CSS Module компонента всегда называется `.root` — это упрощает ориентацию в DevTools и отладку DOM.
|
||||
- Модификаторы — отдельный класс с `_`, применяется через `&._modifier`.
|
||||
|
||||
**Хорошо**
|
||||
```css
|
||||
.submitButton {
|
||||
padding: 8px 16px;
|
||||
|
||||
&._disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```css
|
||||
/* Плохо: kebab-case и вложенный элемент вместо отдельного класса. */
|
||||
.submit-button {
|
||||
padding: 8px 16px;
|
||||
|
||||
&__icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Вложенность
|
||||
|
||||
- Вложенность селекторов запрещена.
|
||||
- Исключения:
|
||||
- Псевдоклассы: `&:hover`, `&:active`, `&:focus`, `&:disabled` и т.д.
|
||||
- Псевдоэлементы: `&::before`, `&::after`.
|
||||
- Медиа-запросы: `@media`.
|
||||
- Модификаторы: `&._active`, `&._disabled`.
|
||||
- Каждый вложенный блок отделяется пустой строкой от предыдущих свойств.
|
||||
|
||||
**Хорошо**
|
||||
```css
|
||||
.card {
|
||||
padding: 16px;
|
||||
background-color: var(--color-bg);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-bg-hover);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
|
||||
&._highlighted {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 16px;
|
||||
|
||||
@media (--md) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```css
|
||||
/* Плохо: вложенность селекторов, нет пустых строк между блоками. */
|
||||
.card {
|
||||
padding: 16px;
|
||||
.cardTitle {
|
||||
font-size: 16px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-bg-hover);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Медиа-запросы
|
||||
|
||||
- Только **Custom Media Queries**: `@media (--md) {}`.
|
||||
- Запрещены произвольные breakpoints: `@media (min-width: 768px)`.
|
||||
- `@media` пишется только **внутри** селектора.
|
||||
- Запрещено писать `@media` на верхнем уровне с селекторами внутри.
|
||||
|
||||
**Хорошо**
|
||||
```css
|
||||
.sidebar {
|
||||
display: none;
|
||||
|
||||
@media (--md) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebarTitle {
|
||||
font-size: 14px;
|
||||
|
||||
@media (--md) {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```css
|
||||
/* Плохо: @media на верхнем уровне с селекторами внутри. */
|
||||
@media (--md) {
|
||||
.sidebar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebarTitle {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Плохо: произвольный breakpoint вместо custom media. */
|
||||
.sidebar {
|
||||
@media (min-width: 992px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CSS-переменные
|
||||
|
||||
- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `src/shared/styles/variables.css` через `:root`.
|
||||
- Файл переменных подключается через `src/shared/styles/global.css`, который импортируется один раз в `src/app/layout.tsx`.
|
||||
- Не дублировать магические значения в компонентах.
|
||||
|
||||
**Хорошо**
|
||||
```css
|
||||
/* src/shared/styles/variables.css */
|
||||
:root {
|
||||
--color-primary: #3b82f6;
|
||||
--color-bg: #ffffff;
|
||||
--color-bg-hover: #f5f5f5;
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--radius-1: 4px;
|
||||
--radius-2: 8px;
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
/* компонент */
|
||||
.card {
|
||||
padding: var(--space-3);
|
||||
border-radius: var(--radius-2);
|
||||
background-color: var(--color-bg);
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```css
|
||||
/* Плохо: магические значения вместо переменных. */
|
||||
.card {
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Media
|
||||
|
||||
- Breakpoints определяются через Custom Media Queries в `src/shared/styles/media.css`.
|
||||
- Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media`) — не импортировать в файлы стилей.
|
||||
|
||||
```css
|
||||
/* src/shared/styles/media.css */
|
||||
@custom-media --sm (min-width: 36em);
|
||||
@custom-media --md (min-width: 62em);
|
||||
@custom-media --lg (min-width: 82em);
|
||||
```
|
||||
|
||||
## Импорт стилей
|
||||
|
||||
- Стили компонента импортируются только внутри своего компонента.
|
||||
- Запрещено импортировать стили одного компонента в другой.
|
||||
- Custom media не импортируются в файлы стилей — они подключаются глобально через конфиг PostCSS.
|
||||
|
||||
## Форматирование
|
||||
|
||||
- Пустая строка между селекторами верхнего уровня.
|
||||
- Пустая строка перед каждым вложенным блоком (медиа, псевдокласс, модификатор).
|
||||
|
||||
**Хорошо**
|
||||
```css
|
||||
.userBar {
|
||||
display: none;
|
||||
color: var(--color-text);
|
||||
|
||||
@media (--md) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.userBarButton {
|
||||
background-color: var(--color-bg);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-bg-hover);
|
||||
}
|
||||
|
||||
&._active {
|
||||
background-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```css
|
||||
/* Плохо: нет пустых строк между селекторами и вложенными блоками. */
|
||||
.userBar {
|
||||
display: none;
|
||||
color: var(--color-text);
|
||||
@media (--md) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.userBarButton {
|
||||
background-color: var(--color-bg);
|
||||
&:hover {
|
||||
background-color: var(--color-bg-hover);
|
||||
}
|
||||
&._active {
|
||||
background-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Единицы измерения
|
||||
|
||||
- `px` — основная единица измерения.
|
||||
- Остальные (`em`, `rem`, `%`, `vh`/`vw`) — допускаются по необходимости дизайна.
|
||||
|
||||
## Порядок CSS-свойств
|
||||
|
||||
В стилях рекомендуется придерживаться логического порядка свойств:
|
||||
|
||||
1. Позиционирование (`position`, `top`, `left`, `z-index`).
|
||||
2. Блочная модель (`display`, `width`, `height`, `margin`, `padding`).
|
||||
3. Оформление (`background`, `border`, `box-shadow`, `border-radius`).
|
||||
4. Текст (`font`, `color`, `text-align`, `line-height`).
|
||||
5. Прочее (`transition`, `animation`, `opacity`, `cursor`).
|
||||
|
||||
## Комментарии
|
||||
|
||||
- Желательно не писать комментарии в CSS.
|
||||
- Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение.
|
||||
Reference in New Issue
Block a user