Перейти к содержимому
EN
Масштаб
Плотность
Тема
Акцент

Ввод

Слайдер

JS по желанию Число рядом с бегунком и заливка дорожки при перетаскивании. Без скрипта слайдер работает целиком, а заливка стоит на значении из разметки

Нативный 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> — дальше он сам.

Без модуля слайдер полностью работает: значение уходит с формой, скринридер объявляет его на каждом шаге. Не обновляется только видимое число.

Пример
6
Разметка
<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-track4pxбаза +4: масштаб
--size-thumb14pxбаза +14: плотность · масштаб
--size-icon18pxбаза +4: масштаб
--tracklight-dark(oklch(0 0 0 / 0.10), oklch(1 0 0 / 0.16))одно на все ячейки
--borderlight-dark(oklch(0 0 0 / 0.12), oklch(1 0 0 / 0.11))одно на все ячейки
--hairline1pxбаза +1: экран
--accent-marklight-dark(var(--a-4), var(--a-3))одно на все ячейки
--surface-raisedlight-dark(var(--n-0), var(--n-12))база +1: тема
--radius-full999pxодно на все ячейки
--dur-180msодно на все ячейки
--ease-outcubic-bezier(0.22, 0.61, 0.36, 1)одно на все ячейки

Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument