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