oscript-ui
oscript-ui

Формы и возвышение

Форма — это скругление углов, возвышение — тень, слой состояния — отклик на наведение и нажатие. Все три в ките — токены Material Design 3: компонент берёт ступень по своей роли и не рисует свою.

Скругления#

Шкала скруглений Material 3 — от прямого угла до пилюли. Чем крупнее и самостоятельнее поверхность, тем мягче её угол.

none
extra-small
small
medium
large
extra-large
full
Ступень Радиус Где в ките
none 0 —
extra-small 4 Выпадающее меню на широком экране
small 8 Поле ввода, тост, блок кода
medium 12 Таблица
large 16 Карточка, карточка объекта, секция настроек, плитка, свёртка, панель сохранения, пустое состояние, свободный край шторки
large-increased 20 —
extra-large 28 Диалог, верхние углы листа меню на телефоне
extra-large-increased 32 —
full 9999 Кнопка, плашка, чип, ход в шапке, пункт дерева разделов, номер страницы, счётчик, тумблер

Токен ступени — --md-sys-shape-corner-<ступень>. Прежние --radius-sm, --radius-md и --radius-lg — псевдонимы extra-small, small и medium.

Множитель радиуса#

Поле Радиус в оформлении умножает все ступени, кроме none и full: пилюля остаётся пилюлей при любом множителе. Допустимы значения от 0,5 до 2, всё остальное заменяется единицей. Посетитель хранит множитель в cookie оформления рядом с темой и акцентом.

ТокеныТемы.БезопасныйМножитель()src/Классы/оформление/ТокеныТемы.os

Пропускает множитель плотности или радиуса в диапазоне [0.5; 2].

Параметры:
 Значение - Произвольный - множитель из профиля или cookie.

Возвращаемое значение:
 Число - множитель либо 1 для значения вне диапазона.

Возвышение#

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

level0
level1
level2
level3
level4
level5
Уровень Где в ките
level0 Всё в потоке страницы без своей поверхности
level1 Карточка, плитка, свёртка (с кольцом), основная кнопка на наведении, лист меню на телефоне
level2 Шапка после прокрутки, выпадающее меню (с кольцом), панель сохранения, карточка-ссылка на наведении (с кольцом)
level3 Диалог
level4, level5 Свободны: для перетаскиваемого и плавающего

Токен уровня — --md-sys-elevation-level<N>. Прежние --shadow-sm, --shadow-md и --shadow-lg — псевдонимы уровней 1, 2 и 3.

Кольцо#

Тень на тёмном фоне почти не видна, поэтому у поверхностей кита есть контур — кольцо: обводка 1 px цветом outline-variant на 60 %, нарисованная тенью без размытия. Кольцо не двигает вёрстку и идёт по скруглению поверхности.

Токен Значение Где в ките
--elevation-ring кольцо Секция настроек — залитая, без тени
--elevation-ring-level1 кольцо и level1 Карточка, карточка объекта, плитка, свёртка
--elevation-ring-level2 кольцо и level2 Выпадающее меню, карточка-ссылка на наведении

Таблицу обводит рамка outline-variant в полную силу, шапку страницы отчёркивает линия того же цвета — в обеих темах.

Глубину в Material даёт прежде всего ступень поверхности: карточка светлее или темнее фона ещё до тени. В тёмной теме тень почти не видна, и поверхность остаётся главной подсказкой — см. поверхности.

Уровень 1 — карточка в потоке страницы

Источники

Три подключённых репозитория.

HTML = Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Тело", "Источники", "<p>Три подключённых репозитория.</p>"));

Уровень 1 и 2 — плитка-ссылка приподнимается на наведении

HTML = Набор.Плитка().Отрисовать(Новый Структура("Значение, Подпись, Адрес", "18", "проектов", "/проекты"));

Слои состояний#

Наведение, фокус и нажатие в Material — не новый цвет, а слой. Поверх заливки ложится цвет её же содержимого с небольшой прозрачностью. Поэтому состояние одинаково читается на любой заливке и в любой теме.

Состояние Токен Material Токен кита
Наведение --md-sys-state-hover-state-layer-opacity 0.08 --state-hover 8%
Фокус --md-sys-state-focus-state-layer-opacity 0.1 --state-focus 10%
Нажатие --md-sys-state-pressed-state-layer-opacity 0.1 --state-pressed 10%
Перетаскивание --md-sys-state-dragged-state-layer-opacity 0.16 --state-dragged 16%
Недоступно, заливка — --state-disabled-container 12%
Недоступно, содержимое — --state-disabled-content 38%

Токены кита — те же доли процентами: в таком виде их принимает color-mix().

Наведите указатель на кнопки — слой ложится на каждую своим цветом.

Слой состояния на заливке, обводке и тексте

HTML = Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Основная", "основная")) + Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Вторичная", "вторичная")) + Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Ссылка", "ссылка")) + Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Заблокирована", "Недоступна", Истина));

Как устроен слой#

Компонент объявляет две локальные переменные: заливку --_bg и цвет содержимого --_fg. Третья, --_state, — плотность слоя: ноль в покое, --state-hover на наведении. Фон считается одной формулой, общей для всех компонентов:

background-color: color-mix(in srgb, var(--_fg) var(--_state), var(--_bg));

Вариант кнопки меняет только пару --_bg и --_fg, правила состояний у всех одни. Прозрачная заливка (кнопка-текст, пункт меню) получает слой тем же путём. Недоступный элемент подменяет пару: заливка — on-surface на 12%, содержимое — on-surface на 38%.

Своему компоненту в листе инсталляции хватит того же приёма:

.report-chip {
	--_bg: var(--md-sys-color-surface-container-low);
	--_fg: var(--md-sys-color-on-surface);
	--_state: 0%;
	color: var(--_fg);
	background-color: color-mix(in srgb, var(--_fg) var(--_state), var(--_bg));
	border-radius: var(--md-sys-shape-corner-small);
	transition: background-color var(--motion-fast) var(--motion-ease);
}
.report-chip:hover { --_state: var(--state-hover); }
.report-chip:focus-visible { --_state: var(--state-focus); }
.report-chip:active { --_state: var(--state-pressed); }

Переменные с подчёркиванием — входы правил состояния внутри одного компонента, а не токены темы. Снаружи их не читайте.

Гайдлайны#

ДелайтеСкругление — ступенью шкалы: кнопки одной формы
Код
HTML = Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Отмена", "вторичная"))
	+ Набор.Кнопка().Отрисовать("Сохранить");
Не делайтеСвоё скругление: кнопка спорит с соседней
Код
HTML = Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Вариант", "Отмена", "вторичная"))
	+ "<button class=""button"" type=""button"" style=""border-radius:3px"">Сохранить</button>";

Источники

Три подключённых репозитория.

ДелайтеТень по высоте слоя: карточка в потоке — уровень 1
Код
HTML = Набор.Карточка().Отрисовать(Новый Структура("Заголовок, Тело",
	"Источники", "<p>Три подключённых репозитория.</p>"));

Источники

Три подключённых репозитория.

Не делайтеТяжёлая тень на карточке в потоке: она будто парит над окном
Код
HTML = "<section class=""card"" style=""box-shadow:var(--md-sys-elevation-level5)"">"
	+ "<h2 class=""card__title"">Источники</h2>"
	+ "<div class=""card__body""><p>Три подключённых репозитория.</p></div></section>";
ДелайтеНедоступное — токенами disabled: ясно, что нажать нельзя
Код
HTML = Набор.Кнопка().Отрисовать(Новый Структура("Подпись, Заблокирована", "Опубликовать", Истина));
Не делайтеНедоступное — прозрачностью всей кнопки: она выглядит живой, но бледной
Код
HTML = "<button class=""button"" type=""button"" disabled style=""--_bg:var(--md-sys-color-primary);"
	+ "--_fg:var(--md-sys-color-on-primary);opacity:.6"">Опубликовать</button>";

Доступность#

  • Фокус с клавиатуры — обводка 3 пикселя цветом secondary с зазором 2 пикселя. Своего скругления у обводки нет: она идёт по форме элемента, и пилюля остаётся пилюлей.
  • Слой фокуса (10%) дополняет обводку, а не заменяет её.
  • Недоступное содержимое на 38% контраст не держит — так задумано в Material: элемент, с которым ничего нельзя сделать, читать не обязательно. Причину недоступности пишите текстом рядом.