Обратная связь
Спиннер
Кольцо, показывающее, что машина занята, когда долю выполненного назвать
нечем. Настоящий SVG из двух окружностей, а не рамка на div.
Разметка
<svg class="inst-spinner" viewBox="0 0 16 16" role="status" aria-label="Загрузка">
<circle class="inst-spinner-track" cx="8" cy="8" r="6.5"/>
<circle class="inst-spinner-arc" cx="8" cy="8" r="6.5"/>
</svg>
Контракт
Разметка фиксирована: viewBox="0 0 16 16", две окружности радиуса 6.5 в
центре 8 8. Копируется целиком.
| Что | Почему нельзя изменить |
|---|---|
viewBox="0 0 16 16" |
Толщина обводки и stroke-dasharray посчитаны под эту систему координат |
r="6.5" cx="8" cy="8" |
Длина окружности при r=6.5 — около 40.8, и 11 30 даёт ровно четверть на дугу |
role="status" |
Иначе появление спиннера ничего не сообщает |
aria-label |
У role="status" должно быть имя: «Загрузка», «Идёт прогон» |
Обе окружности — прямые потомки. Вложить их глубже нельзя: обводка не применится.
Доступность
| Роль | role="status" + aria-label. Спиннер без роли — просто картинка, и для скринридера ожидание не начинается |
| Не единственный носитель | Долгое ожидание сопровождается словами: «Идёт прогон», а не одним крутящимся кольцом |
| Уменьшенное движение | Оборот замедляется до 2.4с, а не останавливается. Схлопнуть анимацию до 0.01ms — это не сжатие длительности, а остановка: спиннер замер бы в случайной фазе, и индикатор перестал бы показывать, что машина занята |
| Контраст | Дуга --accent-mark держит 3:1 против дорожки, а не только против фона |
| Печать | На листе не печатается: печать статична |
Устройство
| Элемент | Работа |
|---|---|
inst-spinner |
<svg>. Размер, толщина обводки, вращение |
inst-spinner-track |
Первая окружность — дорожка, --border-control |
inst-spinner-arc |
Вторая окружность — дуга, --accent-mark. Четверть длины через stroke-dasharray: 11 30 |
Обе окружности одинаковы; отличает их только обводка. Дорожка нужна, чтобы кольцо было видно целиком: одна дуга без неё читается как обрывок.
| Свойство | Значение |
|---|---|
| размер | --size-spinner — 14px; 13px в плотном режиме, 16px в просторном |
| толщина обводки | 2 |
| концы | stroke-linecap: round |
| оборот | 0.7с, линейно, бесконечно |
--accent-mark, а не --accent-text: у тона два передних плана, и метка без
подписи берёт тот, что проверен на 3:1 против дорожки.
Почему SVG
Круг из border-radius на боксе в 13px при дробном DPR растрируется с центром
на полупикселе, и на вращении это видно как биение. У SVG центр задан в
системе координат viewBox, поворот применяется к боксу целиком,
растеризация происходит после — биения нет ни при каком DPR.
API
| Имя | Что делает |
|---|---|
| класс | |
inst-spinner | Базовый. Ставится на <svg> |
inst-spinner-track | Дорожка. Прямой потомок inst-spinner |
inst-spinner-arc | Дуга. Прямой потомок inst-spinner |
| Имя | Значение | Откуда |
|---|---|---|
| токен | ||
--size-spinner | 14px | база +14: плотность · масштаб |
--border-control | light-dark(oklch(0 0 0 / 0.46), oklch(1 0 0 / 0.38)) | одно на все ячейки |
--accent-mark | light-dark(var(--a-4), var(--a-3)) | одно на все ячейки |
Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument