Ввод
Слайдер
Нативный input[type=range], приведённый к метрике кита. Значение выбирают
положением на шкале: слайдер отвечает на «побольше или поменьше», а не на
«сколько именно».
Разметка
<input class="inst-slider" type="range" min="0" max="16" value="6" step="1"
id="agents" aria-label="Параллельных агентов">
Использование
<input class="inst-slider" type="range" min="0" max="100" value="72"
aria-label="Плотность растительности">
| Что | Обязательно | Почему |
|---|---|---|
type="range" |
да | Всё поведение — от платформы: клавиатура, шаг, объявление значения. Класс оформляет нативные псевдоэлементы и на другом типе не делает ничего |
min и max |
да | Без границ шкала неинтерпретируема, а aria-valuemin/max платформа выведет из них сама |
<label for> или aria-label |
да | У слайдера нет собственного текста |
step |
нет | Умолчание — 1. Ставьте явно, когда шаг не единица |
<output for> для числа |
нет | Семантическая связь вместо подписи, меняющейся на каждом шаге |
Слайдер тянется на 100% ширины контейнера. В ряду с другими элементами
дайте ему явный flex и min-inline-size: 0, иначе он вытолкнет соседа на
следующую строку.
Когда использовать
| Используйте | Возьмите другое |
|---|---|
| Приблизительное значение из непрерывного диапазона: громкость, плотность, порог | Точное число, которое вводят цифрами — числовое поле или текстовое поле: попасть бегунком в 47 из 100 нельзя |
| Диапазон, у которого видно оба конца и текущее положение | Значение без известных границ — текстовое поле: у слайдера обязаны быть min и max |
| Настройка, которую крутят и сразу видят результат | Включение и выключение — свитч в переключателях |
| Строка свойства в инспекторе | Показ величины без ввода — мера: слайдер выглядит как контрол и приглашает его тянуть |
Устройство
Бегунок несёт кольцо цвета поверхности и остаётся различимым, когда
наезжает на собственную дорожку. Дорожка берёт --track плюс внутренний
хайрлайн: её протяжённость показывает граница, а не цвет заливки, поэтому
дорожка может оставаться светлой.
| Часть | Токен размера | Замечание |
|---|---|---|
| Дорожка | --size-track, 4px |
--track плюс хайрлайн --border |
| Бегунок | --size-thumb, 14px |
В плотности compact — 12px, в comfortable — 16px |
| Общая высота | --size-icon, 16px |
Чтобы слайдер вставал в строку свойства по той же метрике, что значок |
Нажатие увеличивает бегунок до 1.15 — отклик надо почувствовать, а не
разглядывать.
Заполненной части дорожки у слайдера кита нет: она требует либо
проприетарного ::-moz-range-progress без аналога в Chromium, либо
градиента, пересчитываемого скриптом на каждом шаге. Положение бегунка и есть
значение.
Поведение
Вывод значения
Число рядом с бегунком держит kit.js. Связать положение с текстом
средствами CSS нельзя, поэтому это делает модуль: объявите <output for> —
дальше он сам.
Без модуля слайдер полностью работает: значение уходит с формой, скринридер объявляет его на каждом шаге. Не обновляется только видимое число.
Разметка
<div class="inst-cluster">
<input class="inst-slider" type="range" min="0" max="16" value="6" step="1"
id="sl" aria-label="Параллельных агентов">
<output for="sl">6</output>
</div>
Пример живой: потяните бегунок — число меняет кит.
<output for> связывает число со слайдером семантически, поэтому дублировать
его в aria-label не нужно — и не следует: подпись, меняющаяся на каждом
шаге, превращает объявление в шум.
JS
Подключите модуль один раз на страницу — инициализировать компоненты по отдельности не нужно, кит работает делегированием и видит узлы, пришедшие позже.
<script type="module" src="src/kit.js"></script>
Что делает кит
Пример в разделе «Вывод значения» живой: потяните бегунок, число рядом меняет кит.
Держит в <output for> текущее значение бегунка — при вводе и при загрузке
страницы. Связь уже объявлена атрибутом for; синхронизировать её вручную
значило бы писать одну и ту же строку в каждом приложении.
Без модуля слайдер полностью работает: значение уходит с формой, скринридер объявляет его на каждом шаге. Не обновляется только видимое число.
События
Своих нет — читайте нативный input.
sl.addEventListener('input', (e) => preview.setAgents(+e.target.value));
Методы
refresh(root) проставляет числа заново. Нужно, если разметка пришла в обход
наблюдателя — например, в тесте.
Композиции
В строке свойства
Разметка
<div class="inst-prop">
<span class="inst-prop-label" title="Плотность растительности">Плотность</span>
<span class="inst-prop-control">
<input class="inst-slider" type="range" min="0" max="100" value="72"
aria-label="Плотность растительности">
</span>
</div>
С подписью и подсказкой
Разметка
<div class="inst-field">
<label class="inst-label" for="thr">Порог уверенности</label>
<input class="inst-slider" type="range" min="0" max="100" value="80" step="5"
id="thr" aria-describedby="thr-hint">
<span class="inst-field-hint" id="thr-hint">Ниже порога агент запрашивает подтверждение</span>
</div>
Правила
Так Слайдер для приблизительного
«Побольше или поменьше» — единственный вопрос, на который он отвечает быстрее поля.
Не так Слайдер для точного числа
Попасть бегунком в 47 из 100 зависит от моторики. Там, где число задают точно, нужна пара «слайдер плюс поле».
Так Число через output
<output for> связан со слайдером семантически и не мешает объявлению
значения.
Не так Значение в aria-label
Подпись, меняющаяся на каждом шаге, превращает объявление в шум.
Доступность
| Клавиатура | Стрелки — шаг, PageUp и PageDown — крупный шаг, Home и End — концы диапазона. Всё нативное, кит ничего не перехватывает |
| Роль и значение | slider с aria-valuenow — от платформы. Руками ставить не нужно, а aria-valuetext пригодится, когда число само по себе непонятно: «6 агентов» вместо «6» |
| Имя | <label for> или aria-label. Число выводится через <output>, а не подмешивается в имя |
| Фокус | Нативное кольцо. Оно рисуется вокруг контрола целиком — бегунок 14px кольца не удержал бы |
| Контраст | Бегунок держит 3:1 против поверхности и против дорожки: кольцо цвета поверхности разделяет их там, где они накладываются |
| Цель нажатия | Бегунок 14px — ниже 24px по WCAG 2.5.8, но нажатие принимает дорожка по всей высоте --size-icon, а положение достижимо с клавиатуры. Там, где слайдер единственный способ задать значение, дайте рядом числовое поле |
| Точность | Слайдер не годится для значений, которые надо задать точно: попадание в конкретное число зависит от моторики. Пара «слайдер плюс поле» решает это |
| Уменьшенное движение | Увеличение бегунка при нажатии — переход, а не бесконечная анимация: схлопывается вместе со всеми переходами |
API
| Имя | Значение | Что делает |
|---|---|---|
| класс | ||
inst-slider | — | Единственный класс. Ставится на input[type=range] |
| токен | ||
--size-track | 4px | |
--size-thumb | 14px | |
--size-icon | 16px | |
--track | light-dark(oklch(0 0 0 / 0.10), oklch(1 0 0 / 0.16)) | |
--border | light-dark(oklch(0 0 0 / 0.12), oklch(1 0 0 / 0.11)) | |
--hairline | 1px | |
--accent-mark | light-dark(var(--a-4), var(--a-3)) | |
--surface-raised | light-dark(var(--n-0), var(--n-12)) | |
--radius-full | 999px | |
--dur-1 | 80ms | |
--ease-out | cubic-bezier(0.22, 0.61, 0.36, 1) | |
Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument