Сетка и интервалы
Интервалы кита идут шагом 4dp, как в Material: восемь ступеней от 4 до 64 пикселей. Равнозначные блоки в ряд раскладывает компонент «Сетка», а зазор между соседями всегда задаёт их контейнер.
Шаг 4dp#
Любой отступ и зазор в ките — одна из восьми ступеней. Между ними нет промежуточных значений, поэтому расстояния на экране повторяются и складываются в ритм.
| Токен | Пиксели | Где в ките |
|---|---|---|
--space-1 |
4 | Между полем и пояснением под ним, между плашками в ряду |
--space-2 |
8 | Между кнопками в действиях карточки, плотная сетка |
--space-3 |
12 | Между полями формы, поля шапки |
--space-4 |
16 | Сетка, ритм тела карточки и секции настроек |
--space-5 |
20 | Внутренний отступ карточки и секции, боковые поля страницы |
--space-6 |
32 | Над заголовком раздела, над содержимым страницы |
--space-7 |
48 | Отступ пустого состояния сверху и снизу |
--space-8 |
64 | Под содержимым страницы |
Восемь ступеней шага
--space-1--space-2--space-3--space-4--space-5--space-6--space-7--space-8Строки = "";
Для Номер = 1 По 8 Цикл
Строки = Строки + СтрШаблон("<div style=""display:flex;align-items:center;gap:var(--space-3)"">"
+ "<code style=""flex:none;width:6em"">--space-%1</code>"
+ "<span style=""display:block;height:16px;width:var(--space-%1);"
+ "background:var(--md-sys-color-primary);border-radius:var(--md-sys-shape-corner-extra-small)"">"
+ "</span></div>", Номер);
КонецЦикла;
HTML = "<div style=""display:flex;flex-direction:column;gap:var(--space-2)"">" + Строки + "</div>";Ширина содержимого страницы — --layout-width, 1200 пикселей. Боковые поля — --space-5.
Плотность#
Поле Плотность в оформлении умножает все ступени шага. Допустимы значения от 0,5 до 2, всё остальное заменяется единицей. Посетитель хранит плотность в cookie оформления рядом с темой и акцентом.
Плотность меняет отступы и зазоры, но не высоту управления: кнопка остаётся 36 пикселей, поле — 44. Так экран сжимается, а попадать пальцем и курсором так же легко.
И при единице кит плотнее спецификации Material: он рисует рабочие экраны — списки, формы, настройки, — и на экран должно входить столько же, сколько в прежнем ките 0.9.
| Что | Было, по спецификации | Кит |
|---|---|---|
Текст страницы, body-large |
16 / 24 | 15 / 22 |
Заголовок карточки и секции, title-large |
22 | 20 |
Отступ карточки и секции, --space-5 |
24 | 20 |
| Поле ввода | 56 | 44, подпись наверху — 12 |
| Кнопка, кнопка-значок | 40 | 36 |
| Малая кнопка | 32 | 28 |
| Ход в шапке, пункт колонки разделов | 40 и 48 | 36 |
| Чип | 32 | 28 |
| Плашка | 24 | 22 |
| Ряд таблицы | ≈ 45, шапка 56, ячейка 12 / 16 | ≈ 40, шапка 40, ячейка 10 / 12 |
| Карточка объекта, отступ | 16 / 24 | 12 / 16 |
На телефоне пункт колонки разделов дома настроек остаётся 44 пикселя — под палец.
ТокеныТемы.ПоУмолчанию()src/Классы/оформление/ТокеныТемы.os
Оформление по умолчанию. Возвращаемое значение: Структура - Тема, Акцент, Плотность, Радиус.
Компонент «Сетка»#
Сетка раскладывает равнозначные блоки — карточки, плитки, кнопки — в ряд с переносом. Ячейки приходят готовой разметкой, сама сетка отвечает только за раскладку. Зазор между ячейками — --space-4.
Без поля Колонки ячейка занимает столько, сколько нужно её содержимому, и ряд переносится, когда место кончилось. Так раскладываются плитки сводки.
Авто — плитки сводки
Ячейки = Новый Массив();
Ячейки.Добавить(Набор.Плитка().Отрисовать(Новый Структура("Значение, Подпись, Адрес",
"1 204", "документов", "/документы")));
Ячейки.Добавить(Набор.Плитка().Отрисовать(Новый Структура("Значение, Подпись",
"18", "проектов")));
Ячейки.Добавить(Набор.Плитка().Отрисовать(Новый Структура("Значение, Подпись",
"7", "проектов с источниками")));
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки, Заголовок", Ячейки, "Сводка"));В дереве холста сетка собирается словами (см. Язык узлов): ячейки — дети узла, поля модели — слова Колонки, Плотная, ПолныеРяды, Заголовок.
Узлом холста — словами
HTML = Кит.Сетка(
Кит.Плитка("1 204", "документов").Адрес("/документы"),
Кит.Плитка("18", "проектов"),
Кит.Плитка("7", "проектов с источниками")).Колонки(3).Заголовок("Сводка").Рендер();Колонки#
Колонки — от 1 до 4. Колонки — настоящая CSS-сетка: ширину ячейки задаёт колонка, и она одинакова в любом ряду. У сеток в 3 и 4 колонки число — потолок: шире их не станет ни на каком мониторе, а на узком экране колонок меньше по точкам перелома. Поэтому шесть карточек в трёх колонках всегда заполняют ряды — 3 + 3, 2 + 2 + 2 или по одной, — и хвоста 4 + 2 не бывает.
| Колонки | Для чего | Как ведут себя |
|---|---|---|
| 1 | Стопка блоков | Один столбец |
| 2 | Два блока содержимого рядом: текст и текст, список и список | Колонка не уже 360, пара занимает всю ширину |
| 3 | Сетка карточек | Три колонки одной ширины, даже если карточек меньше трёх; окно до 900 пикселей — две, до 600 — одна |
| 4 | Сетка плиток и мелких карточек | Четыре колонки; окно до 1000 пикселей — три, до 760 — две, до 520 — одна |
Другое значение Колонки сетка не примет: число попадает в класс, поэтому оно сверяется со списком и превращается в «авто».
Две колонки — связи объекта
Ссылается на
отчёт, справочник
Ссылаются сюда
сводка
Ячейки = Новый Массив();
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Тело",
"Ссылается на", "<p>отчёт, справочник</p>")));
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Тело",
"Ссылаются сюда", "<p>сводка</p>")));
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки, Колонки", Ячейки, 2));Карточка в ячейке тянется на всю высоту ряда, а полоса действий встаёт у её нижнего края. Описания разной длины не разводят кнопки по разным линиям.
Три колонки — карточки одной высоты, действия на одной линии
Ячейки = Новый Массив();
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Отчёты", "Сводки по проектам за неделю.",
Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант, Адрес", "Открыть", "ссылка", "/отчёты")))));
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Источники", "Репозитории, из которых собираются пакеты: адрес, ветка, ключ доступа и расписание.",
Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант, Адрес", "Открыть", "ссылка", "/источники")))));
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Доступ", "Участники и роли.",
Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант, Адрес", "Открыть", "ссылка", "/доступ")))));
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки, Колонки", Ячейки, 3));Шесть карточек в трёх колонках ложатся двумя полными рядами; сузьте окно — ряды по две, потом по одной.
Три колонки — шесть карточек заполняют ряды
Отчёты
Раздел проекта.
Источники
Раздел проекта.
Доступ
Раздел проекта.
Ключи
Раздел проекта.
Журнал
Раздел проекта.
Расписание
Раздел проекта.
Ячейки = Новый Массив();
Для Каждого Имя Из СтрРазделить("Отчёты,Источники,Доступ,Ключи,Журнал,Расписание", ",") Цикл
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание",
Имя, "Раздел проекта.")));
КонецЦикла;
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки, Колонки", Ячейки, 3));Полные ряды#
В широкой раскладке три колонки дают широкие и низкие карточки — растянутые и сплюснутые. Четыре колонки им к лицу, но шесть карточек в четырёх колонках ложатся 4 + 2, и второй ряд торчит хвостом. Слово ПолныеРяды решает это без скрипта: на каждой ширине карточки неполного последнего ряда не показываются.
Сколько карточек класть, решает экран, и правило простое — число, которое делится на все ряды. Восемь карточек в Колонки(4).ПолныеРяды():
| Окно | Колонок | Видно |
|---|---|---|
| шире 1000 | 4 | 8 — два ряда по четыре |
| 761–1000 | 3 | 6 — два ряда по три, две последние не показываются |
| 521–760 | 2 | 8 — четыре ряда по две |
| до 520 | 1 | 8 — столбиком |
Почему восемь, а не шесть: шесть в четырёх колонках на широком экране показали бы один ряд из четырёх — две карточки пропали бы там, где места больше всего. Восемь теряют две только на средней ширине, где три колонки. Для трёх колонок то же число — шесть: 3 + 3, на двух колонках — три ряда, на одной — все шесть.
Восемь карточек в четырёх колонках — ряды всегда полные
Сетка = Кит.Сетка().Колонки(4).ПолныеРяды().Заголовок("Разделы проекта");
Для Каждого Имя Из СтрРазделить("Отчёты,Источники,Доступ,Ключи,Журнал,Расписание,Сборки,Выпуски", ",") Цикл
Сетка.Добавить(Кит.Карточка(Имя).Описание("Раздел проекта.").Адрес("/" + НРег(Имя)));
КонецЦикла;
HTML = Сетка.Рендер();Сузьте окно: на средней ширине ряды по три, и седьмой с восьмой карточкой нет; ещё уже — снова все восемь, по две и по одной.
Как это устроено. Число карточек лист не знает, поэтому каждая ячейка находит себя сама: :nth-child — её место в ряду, :nth-last-child — сколько ячеек после неё. Первая ячейка ряда, после которой меньше ячеек, чем колонок, — начало хвоста, и она прячется (display: none) вместе с остальными ячейками хвоста. Правила стоят на тех же точках перелома, что и потолок колонок, и каждое действует только на своём отрезке ширин. Первый ряд не прячется никогда: три карточки в четырёх колонках остаются тремя, а не пустой сеткой.
Слово — только у сеток в 3 и 4 колонки. У двух колонок число рядов зависит от ширины ячейки (auto-fit), а не от точек перелома, и лист не знает, какой ряд неполный: ПолныеРяды у Колонки(1), Колонки(2) и «авто» останавливает сборку.
Секция со списком карточек на телефоне#
На телефоне (до 600 px) карточка или секция, в которой лежит сетка карточек объектов, становится плоской: без кольца, заливки и боковых полей, заголовок и пояснение — на поле страницы. Карточки объектов в ней остаются карточками, как на широком экране, во всю ширину экрана без полей страницы — на 390 это 358 пикселей. Таблица и одиночная карточка внутри карточки — частью родителя, как на странице Карточка.
Секция со списком карточек на телефоне — сузьте окно
Недавно обновлённые
Свежие версии проектов, к которым у вас есть доступ.
отчёты
Сводки за неделю для бухгалтерии.
справочники
Общие справочники всех проектов.
выгрузка
Выгрузка данных во внешние системы.
Ячейки = Новый Массив();
Для Каждого Пара Из СтрРазделить("отчёты:Сводки за неделю для бухгалтерии.,справочники:Общие справочники всех проектов.,"
+ "выгрузка:Выгрузка данных во внешние системы.", ",") Цикл
Имя = СтрРазделить(Пара, ":")[0];
Ячейки.Добавить(Кит.Статья(
Кит.Область(
Кит.Заголовок(3, Кит.Иконка("пакет"), Кит.Ссылка("/проекты/" + Имя, Имя)).Вид("имя"),
Кит.Область(Кит.Плашка("новый").Вид("accent")).Вид("плашки")).Вид("шапка"),
Кит.Примечание(СтрРазделить(Пара, ":")[1]).Вид("описание")).Вид("карточка"));
КонецЦикла;
HTML = Кит.Карточка("Недавно обновлённые", Кит.Сетка(Ячейки[0], Ячейки[1], Ячейки[2]).Колонки(3))
.Иконка("история").Описание("Свежие версии проектов, к которым у вас есть доступ.").Рендер();Плотная сетка#
Плотная уменьшает зазор до --space-2. Она нужна мелким однородным блокам — кнопкам, чипам, — которым обычный зазор велик.
Плотная — кнопки входа
Ячейки = Новый Массив();
Ячейки.Добавить(Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант, Адрес",
"Войти через провайдера 1", "вторичная", "/вход/провайдер-1")));
Ячейки.Добавить(Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант, Адрес",
"Войти через провайдера 2", "вторичная", "/вход/провайдер-2")));
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки, Плотная", Ячейки, Истина));Пустая сетка#
Пустые ячейки сетка пропускает. Если не осталось ни одной, она не печатает ничего — пустая рамка на экран не попадёт. Что показать вместо пустоты, решает экран: обычно это пустое состояние.
Пустая — ничего
этот вызов не печатает ничего
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки", Новый Массив()));Узлом холста#
На холсте сетка — узел, и каждый её ребёнок становится своей ячейкой. Сетка в общем ряду раскладок описана на странице раскладки.
Узлом дерева — ячейки кладут детьми
слева
справа
HTML = Кит.Сетка(
Кит.Примечание("слева"),
Кит.Примечание("справа")).Колонки(2).Рендер();Интервалом владеет контейнер#
У поля, тумблера и других блоков нет собственного внешнего отступа. Расстояние между соседями задаёт тот, кто их держит:
- форма столбиком (
.form-stack) — зазором--space-3; - тело карточки и тело секции настроек — отступом
--space-4над каждым соседом, кроме первого; - сетка — зазором
--space-4или--space-2.
Поля в карточке — ритм даёт тело карточки
Проект
HTML = Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Тело", "Проект",
Набор.Поле().Отрисовать(Новый Структура("Имя, Метка", "название", "Название"))
+ Набор.Поле().Отрисовать(Новый Структура("Имя, Метка", "адрес", "Адрес репозитория"))
+ Набор.Тумблер().Отрисовать(Новый Структура("Имя, Метка, Включено",
"публичный", "Публичный проект", Истина))));Почему не поле: отступ поля складывался с зазором контейнера, и формы дышали двойным ритмом 16 + 12. В строке отбора нижний отступ поля ещё и поднимал его над кнопкой рядом. Один владелец интервала лечит и то, и другое.
Правило формулируется не списком контейнеров, а обязанностью: каждый блок, в котором больше одного поля, задаёт интервал сам. Свой контейнер в листе инсталляции делайте так же:
.report-filters {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
Без display: flex или grid свойство gap не работает — правило выглядит рабочим и ничего не делает.
Тело карточки и секции держит интервал отступом, а не gap: в нём лежит что угодно — таблицы, списки, абзацы — со своими отступами. В обычном потоке отступы соседей схлопываются, и владелец интервала остаётся один. Во флексе они сложились бы с зазором.
Гайдлайны#
Код
HTML = "<div class=""form-stack"">"
+ Набор.Поле().Отрисовать(Новый Структура("Имя, Метка", "имя", "Имя"))
+ Набор.Поле().Отрисовать(Новый Структура("Имя, Метка", "почта", "Почта"))
+ "</div>";Код
HTML = "<div>"
+ Набор.Поле().Отрисовать(Новый Структура("Имя, Метка", "имя", "Имя"))
+ Набор.Поле().Отрисовать(Новый Структура("Имя, Метка", "почта", "Почта"))
+ "</div>";Код
HTML = "<div style=""display:flex;gap:var(--space-2)"">"
+ Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Назад", "вторичная"))
+ Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Пропустить", "вторичная"))
+ Набор.Кнопка().Отрисовать("Далее")
+ "</div>";Код
HTML = "<div style=""display:flex"">"
+ Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Назад", "вторичная"))
+ "<span style=""width:3px""></span>"
+ Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Пропустить", "вторичная"))
+ "<span style=""width:13px""></span>"
+ Набор.Кнопка().Отрисовать("Далее")
+ "</div>";Отчёты
Сводки за неделю.
Источники
Репозитории, ветки, ключи доступа и расписание сборки.
Код
Ячейки = Новый Массив();
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Отчёты", "Сводки за неделю.", Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Открыть", "ссылка")))));
Ячейки.Добавить(Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Источники", "Репозитории, ветки, ключи доступа и расписание сборки.",
Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Открыть", "ссылка")))));
HTML = Набор.Сетка().Отрисовать(Новый Структура("Ячейки, Колонки", Ячейки, 2));Отчёты
Сводки за неделю.
Источники
Репозитории, ветки, ключи доступа и расписание сборки.
Код
HTML = "<div style=""display:flex;align-items:flex-start;gap:var(--space-4)"">"
+ Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Отчёты", "Сводки за неделю.", Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Открыть", "ссылка"))))
+ Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Описание, Действия",
"Источники", "Репозитории, ветки, ключи доступа и расписание сборки.",
Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Открыть", "ссылка"))))
+ "</div>";Доступность#
Заголовоксетки печатаетсяaria-label: скринридер назовёт группу блоков («Сводка»), прежде чем читать их.- Порядок ячеек в разметке — порядок чтения. Сетка его не переставляет: на узком экране блоки идут столбцом в том же порядке.
- Плотность ниже единицы сжимает зазоры, но не цели нажатия: высота кнопки и поля от неё не зависит.
- Карточка, которую
ПолныеРядыне показывает, скрыта и от скринридера (display: none). Сетка с полными рядами — витрина, а не единственный путь: всё, что в ней может не показаться, должно быть доступно и по ссылке «Все…» под ней.
Модель#
Структура ниже — прежний вид модели: её получает набор, а в дереве холста те же поля задают слова Колонки, Плотная, ПолныеРяды и Заголовок.
Сетка.Отрисовать()src/Классы/компоненты/Сетка.os
Отрисовывает сетку равнозначных блоков.
Параметры:
Модель - Структура - Ячейки (массив: ДОВЕРЕННЫЙ HTML строкой либо структура с полем
HTML; пустые пропускаются), Колонки ("авто" | 1 | 2 | 3 | 4; 1 — стопка
в один столбец), Заголовок (aria-label области), Плотная (уменьшенный зазор),
ПолныеРяды (только у 3 и 4 колонок: ячейки неполного последнего ряда на каждой
ширине не показываются — ряды всегда полные).
Возвращаемое значение:
Строка - фрагмент <div class="grid"> либо "" для пустого набора ячеек.Кит.Сетка()src/Классы/холст/Кит.os
Сетка равнозначных блоков: КАЖДЫЙ ребёнок узла становится своей ячейкой. Слова:
Колонки, Плотная, ПолныеРяды, Заголовок.
Параметры:
Р1…Р8 - ЭлементЭкрана, Структура - (необязательные) ячейки сетки; Структура первым
аргументом — прежний вид модели без поля Ячейки.
Возвращаемое значение:
ЭлементЭкрана