Фокус
Кольцо фокуса показывает, где находится человек, который работает с клавиатуры. Framework задаёт одно кольцо на всю систему, поэтому оно одинаково видно в любом компоненте и меняется в одном месте.
Одно кольцо на всю систему
Клавиатурный фокус — единственное, по чему человек без мыши понимает, где он находится. Поэтому кольцо в Framework одно: компонент его не изобретает, а берёт четыре переменные:
| Переменная | Значение | Почему |
|---|---|---|
--sf-focus--width |
2 px | Нижняя граница площади индикатора по WCAG 2.2; кольцо в 1 px её не набирает |
--sf-focus--style |
solid |
Полупрозрачное кольцо даёт контраст 1,4:1 вместо нужных 3:1 |
--sf-focus--offset |
1 px | Зазор показывает поверхность за контролом, и кольцу есть на чём читаться |
--sf-focus--color |
роль --sf-focus (Служебные роли) |
Проект меняет её один раз, и это действует везде |
Ширина и зазор кольца заданы в пикселях, через --sf-px, а не в rem. Кольцо
остаётся сплошной линией 2 px с зазором 1 px при любом корневом кегле и не
растёт вместе с ним.
Пример показывает, из чего собрано кольцо. Глобальное правило ядра уже рисует его на любом элементе с фокусом (Особые случаи), поэтому своё правило контролу проекта нужно, только если кольцо должно отличаться:
.project-control:focus-visible {
outline: var(--sf-focus--width) var(--sf-focus--style) var(--sf-focus--color);
outline-offset: var(--sf-focus--offset);
}
Значения подобраны по измерениям. Например, кольцо вплотную к переключателю на синей дорожке даёт контраст 1,0:1, а зазор в один пиксель это исправляет.
Только с клавиатуры
Кольцо появляется через :focus-visible, то есть при работе с клавиатуры. При
щелчке мышью его нет: место назначения и так видно.
- Нельзя подменять
:focus-visibleна:focus: кольцо начнёт появляться на каждом щелчке.
Кольцо — контур, а не тень
Кольцо рисуется свойством outline. Тень для этого не подходит: она делит
свойство с высотой элемента, рисуется поверх соседей и пропадает в режиме
высокой контрастности. Токен --sf-ui-focus — теневое кольцо; он сохранён
для совместимости, новых мест ему не отдают.
В утилитах тот же выбор: focus-visible:outline-* рисует настоящий контур, а
focus-visible:ring-* — тень (Кольцо). Для
кольца фокуса берите контур. Префикс focus: срабатывает и после щелчка
мышью, поэтому для кольца фокуса берите focus-visible:. В режиме высокой контрастности (forced-colors)
кольцо рисуется системным цветом: цветом текста элемента или цветом выделения
Highlight. Цвет контура в этом режиме подменяет сам браузер, поэтому
кольцу собственного контрола проекта ничего добавлять не нужно.
Особые случаи
-
Элемент вплотную к соседям (сегмент группы кнопок, вкладка, ячейка календаря, строка списка). Внешнее кольцо закрыло бы соседа или его обрезал бы контейнер с прокруткой, поэтому кольцо поворачивается внутрь:
outline-offset: calc(var(--sf-focus--width) * -1). -
Залитый элемент. Заливка может оказаться соседней ступенью той же палитры, что и кольцо. Например, в тёмной теме контраст кольца к заливке основной кнопки — 1,31:1. Поэтому залитая кнопка рисует внутри вторую линию цветом своей подписи: он контрастен заливке по построению. Линия складывается с тенью высоты кнопки, а не заменяет её.
-
Собственный контрол проекта. Глобальное правило ядра
:focus-visible { outline: … var(--sf-focus--*) }стоит в слоеsf.baseи рисует кольцо на любом элементе, который получил фокус с клавиатуры, в том числе на элементе проекта сtabindex="0"илиrole="button". Своё правило:focus-visibleконтролу проекта нужно, только если кольцо должно отличаться, например поворачиваться внутрь. То же кольцо рисует и класс.focus-visible. -
Кто владеет кольцом. Глобальное правило красит элемент, который держит фокус. Если компонент рисует кольцо на видимой обёртке (у поля это рамка поля, у флажка — коробка, у переключателя — дорожка), он обязан снять кольцо с нативного элемента внутри. Иначе колец будет два:
.project-field:has(input:focus-visible) .project-field-box { outline: var(--sf-focus--width) var(--sf-focus--style) var(--sf-focus--color); outline-offset: var(--sf-focus--offset); } .project-field input:focus-visible { outline: none; }
Правило:
- Нельзя убирать кольцо без равноценной замены:
outline: noneв одиночку делает элемент невидимым для клавиатуры. - Нельзя рисовать кольцо тенью: оно закроет соседа и пропадёт в режиме высокой контрастности.
- Нельзя заводить свой цвет кольца: проект меняет роль
--sf-focusодин раз, и это действует везде.
Смотрите также
- Служебные роли — роль цвета
--sf-focus. - Высота: поверхность и тень — тень высоты.
- Ссылки — фокус у ссылок.