Слой состояния (State Layer)
Источник:
ds-docs/component-contracts/foundations/state-layer.md
Слой состояния — полупрозрачное покрытие, которое делает в макете две работы разом: показывает наведение, нажатие и фокус — и обозначает область нажатия компонента. Вторая работа не очевидна, но в Astra DS она главная: слой отвечает на вопрос «по чему именно здесь нажимают — по всей строке или только по значку».
Это приём дизайна, а не устройство компонента. Он заведён, чтобы не плодить лишние слои и варианты в и без того тяжёлых компонентах: вместо отдельных мастеров на наведение и нажатие — один слой, вместо невидимой обоймы «зона клика» — он же.
Наверх — фундаменты. Рядом: цвет, светлая тема, движение.
Два вида в макете
В файле слой встречается в двух видах, и путать их нельзя.
1. Обойма State layer … — тело компонента
Обычная обойма с раскладкой, внутри которой лежит всё содержимое. Красится токеном
по состоянию: в покое заливки нет, в наведении и нажатии появляется. Имя всегда
начинается со слов State layer, дальше идёт уточнение вида: State layer Small Text,
State layer Medium, State layer Text+Icon.
Так устроены 53 компонента: кнопка, значок-кнопка, чипы, фильтры, вкладки, все поля ввода, флажок, переключатель, ячейки календаря, клавиша клавиатуры.
2. Инстанс ⚒︎ State Layer — область нажатия
Отдельный служебный компонент (28007:16437, страница Color Tokens). Сам по себе
прозрачен — в макете его не видно, найти можно только по имени.
Областью нажатия он становится, когда лежит абсолютно и растянут по родителю. Поверх всей строки — нажимают по строке целиком; поверх одной обоймы — только по ней. Так его используют 12 компонентов: строка списка и её варианты с перетаскиванием и смахиванием, строка аккордеона, кнопка-плитка, баннеры, строка загруженного файла, картинка в загрузчике.
Но не всякая его вставка — область нажатия. Тот же компонент кладут в поток раскладки просто как крашеный прямоугольник:
Button Bannerв состоянии загрузки набирает им полосы-заглушки вместо текста (State=Skeleton, размеры 82×12 и 96×10 — под строку) и серую пелену поверх всего баннера (State=Disabled). Это 156 вставок из 159 «в потоке» по всей системе;Image Upload Itemкладёт слой в поток, но его родитель абсолютен и слой заполняет его целиком — по действию это всё-таки область нажатия.
Отличать одно от другого просто: position: absolute плюс размер родителя — область
нажатия; всё прочее — покраска.
У инстанса своя ось State с пятью значениями:
Default | прозрачен — компонент нажимается, но не подсвечен |
Hovered | заливка hover-bg-dark |
Pressed | заливка press-bg-dark |
Disabled | заливка bg-layer-disabled-02 |
Skeleton | внутрь кладётся заглушка загрузки Skeleton |
В самих компонентах используются только три из пяти: Default (177 вставок),
Skeleton (104) и Disabled (52). Hovered и Pressed у инстанса не встречаются
ни разу — эти состояния показывают обоймой первого вида.
Как читать пример: строка списка
Basic List Item — образец, на котором видно оба вида сразу:
Basic List Item корень, заливка bg-list-primary
State layer ← обойма: тело строки, держит содержимое и поля
⚒︎ State Layer absolute 375×72 ← инстанс: область нажатия во всю строку
[Left Container] / ✱ Icon Container
Middle Container / [Text Container] / …
[Right Container] / Checkbox
Divider
Читается так: нажимают по всей строке, а не по значку и не по подписи — потому что слой растянут по телу строки, а не по её части. Разделитель снизу в область нажатия не входит: он лежит вне обоймы.
И ещё одно, что видно только по мастерам: инстанс стоит лишь в состоянии Default.
В Read Only и Skeleton его нет — строка перестаёт нажиматься. То есть присутствие
слоя и есть признак «здесь можно нажать».
Значения по состояниям
Одни и те же для любого фона: слой добавляет прозрачность поверх.
Hover | +4 % | hover-bg-dark, на тёмном фоне hover-bg-light |
Focus | +8 % | focus-bg |
Press | +16 % | press-bg-dark, на тёмном фоне press-bg-light |
Drag | +16 % | отдельного токена нет |
Что стоит за токенами — цвет, светлая тема.
Что из этого проверяет плагин
Правило порядка слоёв («контейнер → слой состояния → контент») относится только к пустой
обойме-подкраске: у обоймы с содержимым внутри порядок ни при чём, а служебный инстанс
лежит абсолютно поверх нарочно. Плагин проверки так и настроен — LAY-001 в каталоге правил.
Проверяемое отклонение здесь другое и записано ниже: чем слой красится в своём состоянии.
Это LAY-002; по базе он находит те же два случая, что нашёл аудит.
Где правило нарушено
Проверка по всем 284 контрактам базы нашла четыре отклонения:
Numkey: в состоянииFocusedкладётсяhover-bg-darkвместоfocus-bg;Tab Item: в состоянииPressedкладётсяfocus-bgвместоpress-bg-dark;Icon Button: наведение, нажатие и фокус привязаны к переменным3174:6492,7468:21293и7468:21292, которых нет в выгрузке токенов — имени у них нет;- имя состояния пишется по-разному:
HoveredиHover,Pressed,FocusedиFocus— в одной системе четыре словаря на три состояния.
Как это попадает в контракт
Оба вида помечаются одинаково — полем foundation: state-layer. Метка говорит
разработчику: перед ним не обычная обойма, а слой состояния, и читать его надо
по правилам этого документа.
Обойма:
- path: Basic List Item/State layer
kind: frame
foundation: state-layer
layout: {direction: row, mainAlign: start, crossAlign: center, gap: space-m, …}
size: {width: fill, height: hug}
fill: none # в наведении — hover-bg-dark, в нажатии — press-bg-dark
Инстанс:
- path: "Basic List Item/State layer/⚒︎ State Layer"
kind: instance
of: state-layer
foundation: state-layer
position: absolute
size: {width: 375, height: 72}
props: {State: Default}
position: absolute вместе с меткой читается как «область нажатия — весь родитель».
Какой именно родитель — видно по пути узла. Без position: absolute метка значит только
«здесь тот самый служебный компонент»: областью нажатия он не работает.
Валидатор следит за единообразием: узел, чьё имя начинается с State layer или
⚒︎ State Layer, без метки даёт предупреждение.
Реализация в коде
Одна концепция, две платформы.
React (core-ui)
Смешивание цветов заранее записано в CSS-переменные: у каждого цвета есть -hover
и -pressed. Именование: var(--<токен-фона>-hover), var(--<токен-фона>-pressed).
Когда фон прозрачный, а состояния нужны, берутся --hover-bg-dark и --press-bg-dark —
те же токены, что кладёт макет на слой.
.secondary {
background-color: var(--button-secondary-bg);
@media (hover: hover) and (pointer: fine) {
&:not(:disabled):hover { background-color: var(--button-secondary-bg-hover); }
}
&:not(:disabled):active { background-color: var(--button-secondary-bg-pressed); }
}
/* прозрачный фон → слой состояния */
.ghost {
background-color: var(--transparent);
@media (hover: hover) and (pointer: fine) {
&:not(:disabled):hover { background-color: var(--hover-bg-dark); }
}
&:not(:disabled):active { background-color: var(--press-bg-dark); }
}
Область нажатия в код переносится не слоем, а размером самого интерактивного узла:
если в макете слой растянут по строке, в коде по строке растянут button или a,
а не вложенный значок.
Flutter
Смешивание задаётся обёрткой анимации цвета ButtonColorAnimated: базовый цвет плюс
подмешиваемые hover, press, focus.
return ButtonColorAnimated(
onTap: isLoading ? () {} : onTap,
unpressedColor: _isDisabled ? colors.disabled : colors.unpressed,
hoverBlendedColor: colors.hover,
pressBlendedColor: colors.press,
focusBlendedColor: colors.focus,
builder: (Color? color) => DecoratedBox(
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(borderRadius)),
// …
),
);
Открытые вопросы
- Q-1 — Flutter: полное описание поведения (источники цветов состояний) — запросить у команды Flutter.
- Q-2 — у
Dragсвоего токена нет, хотя в правиле он есть: чем его показывать. - Q-3 — три переменные
Icon Button(3174:6492,7468:21293,7468:21292) не найдены в выгрузке токенов: живые ли они. - Q-4 — словарь состояний: свести
Hover/Hovered,Press/Pressed,Focus/Focusedк одному написанию.
Источник
Концепция, значения прозрачности и примеры кода — PDF «Слои состояния» (Astra DS),
перенос 06.08.2026. Устройство в макете, перепись по компонентам и отклонения — разбор
оригинала eGpqY0OqVR8l8zhmlHdfb9 по контрактам, 07.09.2026. Та же копия документа лежит
в старой библиотеке: ../foundations/state-layer.md;
на неё ссылаются 90 карточек компонентов.