noUiSlider: диапазоны и настройки интерфейса — 6 интерактивных примеров
Мини-мастерская noUiSlider и шесть готовых интерфейсов: фильтр цены, бронирование, сроки хранения, нелинейная шкала, распределение времени и RGB. Настройки, код и исходники.

Выбрать цену от и до, ограничить длительность записи, распределить время между этапами — это разные задачи, хотя во всех можно использовать ползунок. noUiSlider управляет ручками, диапазоном и ограничениями, а приложение решает, что делать с выбранными числами: фильтровать карточки, пересчитывать объём или менять оформление.
В этой статье два рабочих блока. Сначала конструктор самого ползунка: меняйте диапазон, шаг и количество ручек, затем скачивайте HTML. После него — шесть прикладных интерфейсов с точным вводом, результатом, сбросом и кодом. Примеры работают на настоящем noUiSlider 15.8.1; библиотека и стили размещены вместе с мастерской на нашем сервере.
- В конструкторе выберите «Диапазон» и измените шаг.
- В каталоге установите 5 000–7 000 ₽ и посмотрите, какие карточки останутся.
- В бронировании сравните перемещение одной ручки и всего интервала.
- Откройте JSON или код выбранного примера и сохраните результат.
Все товары, цены и настройки демонстрационные. Здесь нет реального бронирования, удаления копий или изменения конфигурации сервера. Значения обрабатываются в браузере; мастерская показывает, как построить понятный интерфейс вокруг библиотеки.
1. noUiSlider и обычный input type=”range”
Для одного простого числа часто достаточно стандартного HTML-поля. Оно уже умеет минимум, максимум, шаг и управление с клавиатуры. noUiSlider становится полезен, когда нужны несколько связанных ручек, выделенный интервал, нелинейная шкала или ограничения расстояния между границами.
| Задача | Обычный range | noUiSlider |
|---|---|---|
| Одно значение | Подходит без дополнительной библиотеки | Подходит, но добавляет зависимость |
| Цена от и до | Нужно согласовывать два поля самостоятельно | Две ручки и соединённый диапазон |
| Минимальная и максимальная длительность | Логика ограничений пишется приложением | Есть margin и limit |
| Несколько границ | Потребуется собственная композиция контролов | Несколько ручек в одном компоненте |
| Нелинейная шкала | Нужно преобразование координаты в значение | Контрольные точки и шаги в range |
| Сохранение формы | Поле с name входит в FormData | Значения нужно явно перенести в поля или запрос |
Сравнивайте удобство на своей задаче. Для громкости от 0 до 100 стандартное поле может быть достаточным. Для выбора интервала с ограничениями библиотека сокращает код управления, но подписи, проверки, результат и серверная логика всё равно остаются частью приложения.
<label for="intensity">Интенсивность</label>
<input id="intensity" name="intensity"
type="range" min="0" max="100" step="5" value="40">
<output id="intensity-value" for="intensity">40</output>
<script>
const input = document.getElementById('intensity');
const output = document.getElementById('intensity-value');
input.addEventListener('input', () => {
output.value = input.value;
});
</script>
Подробнее: noUiSlider: возможности и подключение.
2. Конструктор: настройте сам ползунок
Этот стенд помогает понять параметры библиотеки до внедрения в интерфейс. Есть три отправные точки: одно значение, диапазон и три границы. Меняйте минимум, максимум, шаг, число ручек, начальные значения и отображение подсказок. Кнопка «Применить настройки» отделяет редактируемые поля от работающего результата.
Попробуйте: у диапазона 0–100 установите шаг 10 и начальные значения 20; 80. Примените настройки, затем передвиньте ручку стрелкой на клавиатуре. После этого выберите «Три границы» и посмотрите, как одна средняя ручка меняет два соседних участка.
Числа в поле начальных значений разделяются точкой с запятой; для десятичной части используется точка. Под результатом есть точный ввод: он полезен, когда нужное значение трудно попасть перетаскиванием. Ошибочная конфигурация должна быть исправлена до применения.
В блоке кода переключите JSON на «Полный HTML». Экспорт содержит разметку, стили и библиотеку, поэтому скачанную страницу можно открыть без интернета. В файл попадают применённые настройки и текущие значения ручек; незавершённые правки полей настроек сначала нужно применить.
3. Шесть интерфейсов: от значения к результату
Теперь ползунок управляет конкретной задачей. Вкладки переключают каталог, бронирование, хранение, объём, план и цвет. У каждого примера своё состояние; «Сбросить пример» возвращает исходные параметры выбранного сценария.
Сначала измените значение и посмотрите на результат. Затем раскройте JSON, готовый HTML + JavaScript или последние действия. JSON содержит данные текущего примера, а код позволяет перенести его в свой проект. В архиве также находятся общая мастерская и локальные зависимости.
Скачать исходники всех примеров ZIP. Для запуска мастерской распакуйте архив и откройте его через локальный HTTP-сервер. Полный HTML из конструктора выше — отдельный вариант экспорта со встроенной библиотекой.
Короткие фрагменты ниже показывают ключевую идею каждого сценария. Это части обработчиков, а не самостоятельные приложения: в них предполагаются уже созданный ползунок и соответствующие элементы страницы. Полную разметку и запускаемый код удобнее брать из мастерской.
4. Каталог: диапазон цены и пустая выдача
Такой интерфейс пригодится в каталоге услуг, магазине или подборе оборудования. Две ручки задают включительные границы: карточка остаётся, если её цена не меньше нижней и не больше верхней. Значение рядом с ползунком и число найденных карточек объясняют результат без чтения JSON.
Проверка: примените 5 000–7 000 ₽ — останутся «Форма записи» за 5 200 ₽ и «Личный кабинет» за 6 800 ₽. Диапазон 1 000–1 200 ₽ даст пустую выдачу с объяснением и сбросом. Ограничения примера: 0–10 000 ₽, шаг 100 ₽.
// priceSlider — элемент, на котором уже создан noUiSlider.
priceSlider.noUiSlider.on('update', (values, handle, raw) => {
const [minPrice, maxPrice] = raw;
const visible = products.filter(product =>
product.price >= minPrice && product.price <= maxPrice
);
renderCards(visible);
count.textContent = visible.length + ' из ' + products.length;
emptyState.hidden = visible.length !== 0;
});
Библиотека ограничивает ручки и выдаёт числа. Фильтрация массива, карточки, счётчик и пустое состояние написаны отдельно. В реальном каталоге вместо локального массива можно отправлять диапазон серверу; для сетевых запросов лучше выбрать момент завершения действия и обработать устаревшие ответы, чтобы быстрые движения не подменили новую выдачу старой.
Не скрывайте фильтр вместе с пустыми результатами: пользователю нужен способ расширить границы. Ручной ввод двух цен проверяйте вместе, особенно условие «от ≤ до».
Попробовать фильтр и пустую выдачу ↑
5. Бронирование: связанные границы времени
Пример подходит для выбора времени аренды или записи на услугу. Внутри модели хранятся минуты одного условного дня: 09:00 — это 540, 18:00 — 1080. Формат HH:mm используется только для вывода. Так проще задавать шаг и длительность обычными числами.
Проверка: приблизьте ручки — интервал не станет короче 60 минут. Раздвиньте — он не превысит 240 минут. Шаг составляет 15 минут. Выделенный отрезок можно двигать целиком. Начальный выбор 10:00–12:00 означает 120 минут.
noUiSlider.create(bookingSlider, {
start: [600, 720],
range: { min: 540, max: 1080 },
step: 15,
margin: 60,
limit: 240,
connect: true,
behaviour: 'tap-drag'
});
bookingSlider.noUiSlider.on('update', (values, handle, raw) => {
const [startMinutes, endMinutes] = raw;
duration.textContent = (endMinutes - startMinutes) + ' мин';
selectedInterval = null; // Изменённый выбор нужно подтвердить заново.
});
margin задаёт минимальное расстояние между соседними ручками, limit — максимальное. Это не проверка календаря или занятости. Выходные дни, часовой пояс, переход через полночь и доступность места потребуют отдельной модели.
Кнопка «Выбрать интервал» подтверждает текущий выбор только внутри примера. Если после этого поменять время, прежнее подтверждение перестаёт быть актуальным. В рабочем сервисе результат бронирования показывают после ответа сервера, а не после одного движения ползунка.
Подробнее: margin, limit и поведение ручек.
6. Настройки сервиса: только разрешённые варианты
Иногда между 7 и 14 нет допустимых промежуточных значений. Например, продукт предлагает заранее определённые политики хранения: 1, 3, 7, 14, 30 и 90 дней. Здесь ползунок перемещается по индексам 0–5, а конфигурация получает реальный срок из массива.
Проверка: выберите «14 дней» в точном списке. В JSON появится retentionDays: 14. Кнопки «Неделя», «Месяц» и «Квартал» выбирают те же значения через API. Наглядная линия показывает контрольные точки, попадающие в срок; никаких файлов пример не удаляет.
const policies = [1, 3, 7, 14, 30, 90];
noUiSlider.create(retentionSlider, {
start: 2,
range: { min: 0, max: policies.length - 1 },
step: 1,
connect: 'lower'
});
retentionSlider.noUiSlider.on('update', (values, handle, raw) => {
const index = Math.round(raw[0]);
config.retentionDays = policies[index];
});
// Кнопка «Месяц».
retentionSlider.noUiSlider.set(policies.indexOf(30));
Этот приём подходит для сроков, размеров пакета и уровней качества с фиксированным перечнем. Равные расстояния здесь означают соседние варианты, а не равное число дней. Поэтому рядом нужны явные подписи и точный список; отправлять индекс 3 как срок 3 дня было бы ошибкой.
7. Нелинейная шкала: большой диапазон без потери точности
Если диапазон тянется от 10 до 10 000, одинаковый шаг и равномерная шкала неудобны для небольших значений. В примере первые 35% длины отданы диапазону 10–100, следующий участок до 70% — значениям 100–1 000, оставшаяся часть — до 10 000.
Проверка: введите 456 при размере пакета 250. После применения получите 460 по шагу 10. Для этого нужны два пакета; в последнем занято 210 из 250 единиц, то есть 84%. Сообщение об округлении объясняет изменение введённого числа.
noUiSlider.create(capacitySlider, {
start: 600,
connect: 'lower',
range: {
min: [10, 1],
'35%': [100, 10],
'70%': [1000, 100],
max: 10000
}
});
function calculatePackages(volume, packageSize) {
const count = Math.ceil(volume / packageSize);
const last = volume - (count - 1) * packageSize;
return { count, last, percent: last / packageSize * 100 };
}
В массиве контрольной точки первое число — значение, второе — шаг начинающегося участка. Половина ширины такого ползунка не означает половину числового диапазона. Не подписывайте положение в процентах как процент выбранного объёма.
noUiSlider отвечает за преобразование позиции в число. Расчёт количества пакетов и заполнения написан отдельно и использует фактическое значение после округления. Условные единицы не описывают производительность настоящего сервера; смысл и размер пакета определяются вашим продуктом.
Подробнее: контрольные точки и шаги нелинейного диапазона.
8. Планирование: четыре доли из трёх границ
Три ручки делят 100% на разработку, проверку, документацию и резерв. Начальные границы 50 / 75 / 90 означают доли 50 / 25 / 15 / 10. Это полезно для распределения времени и квот, когда сумма должна оставаться постоянной.
Проверка: оставьте 40 часов и измените среднюю границу с 75 на 80. Доли станут 50%, 30%, 10% и 10%; проверка получит 12 часов, документация — 4. Каждый этап занимает минимум 5%, а порядок границ сохраняется.
function getShares([first, second, third]) {
return [first, second - first, third - second, 100 - third];
}
const shares = getShares([50, 80, 90]); // [50, 30, 10, 10]
const hours = shares.map(percent => percent * 40 / 100);
// [20, 12, 4, 4]
// Основные настройки ползунка:
const options = {
start: [50, 75, 90],
range: { min: 0, max: 100 },
step: 1, margin: 5, padding: 5,
connect: [true, true, true, true]
};
margin: 5 сохраняет минимальные внутренние промежутки, а padding: 5 оставляет место у обоих краёв. Цветная полоса помогает быстро оценить распределение; таблица с названиями, долями и часами даёт точное значение и не заставляет различать этапы только по цвету.
Не отправляйте положения ручек как готовые доли. Сначала вычислите разности. Округление времени для отображения также отделяйте от модели: в приложении с минутами или деньгами нужно заранее выбрать единицу расчёта и правило распределения остатка.
9. Оформление: три регулятора и один результат
В микшере три независимых ползунка задают каналы RGB от 0 до 255. Изменяется акцент карточки, рядом видны HEX, RGB и готовая CSS-переменная. Такой приём пригодится в редакторе темы, конструкторе виджета и настройках оформления.
Проверка: примените 0 / 0 / 0 — получится #000000. Пресет «Белый» устанавливает #FFFFFF. Изменение одного канала сохраняет два других. Цвет страницы статьи при этом не меняется.
function toHex(rgb) {
return '#' + rgb.map(value =>
value.toString(16).padStart(2, '0')
).join('').toUpperCase();
}
const rgb = [34, 115, 105];
const hex = toHex(rgb); // #227369
preview.style.setProperty('--accent-color', hex);
cssOutput.textContent = '--accent-color: ' + hex + ';';
Функция предполагает уже проверенные целые числа 0–255. Проверка полей, синхронизация трёх компонентов и генерация CSS — логика приложения. Библиотека управляет отдельными регуляторами. В демонстрации текст образца выбирается светлым или тёмным; это не заменяет проверку контраста всей будущей страницы.
10. Подключение: обычный HTML и npm
Для страницы без сборщика сохраните JavaScript и CSS одной версии библиотеки рядом с проектом. В архиве они уже находятся в assets/vendor/. Создавайте ползунок после появления его элемента в DOM: например, в скрипте с defer или после разметки.
<link rel="stylesheet" href="assets/vendor/nouislider.min.css">
<label id="limit-label">Лимит</label>
<div id="limit"></div>
<output id="limit-value">40</output>
<script src="assets/vendor/nouislider.min.js"></script>
<script>
const slider = document.getElementById('limit');
const output = document.getElementById('limit-value');
noUiSlider.create(slider, {
start: 40,
step: 5,
range: { min: 0, max: 100 },
connect: 'lower',
handleAttributes: [{ 'aria-labelledby': 'limit-label' }]
});
slider.noUiSlider.on('update', (values, handle, raw) => {
output.value = raw[0];
});
</script>
Для проекта со сборщиком установите пакет:
npm install nouislider@15.8.1
import noUiSlider from 'nouislider';
import 'nouislider/dist/nouislider.css';
// Здесь создавайте ползунок после появления его DOM-элемента.
Такой импорт CSS предполагает инструмент сборки, который умеет его обрабатывать. Он не эквивалентен вставке этих строк в обычный тег script. Для быстрого переноса без настройки сборки удобнее полный HTML из конструктора.
В WordPress мастерская изолирована в iframe: её Bootstrap и оформление не меняют меню или формы других публикаций. Основной текст статьи остаётся обычным HTML с заголовками для штатного оглавления.
11. События и API: update, change и set
| Событие | Когда полезно | Типичное применение |
|---|---|---|
update |
Значение изменилось; обработчик также вызывается сразу при подписке | Поля, подписи и локальный предпросмотр |
change |
Пользователь завершил изменение перетаскиванием, касанием или клавиатурой | Запрос данных после действия пользователя |
set |
Значение установлено, в том числе программным API | Реакция и на пользователя, и на установку из кода |
Для плавного локального результата используйте update. Но не считайте каждый его вызов новой пользовательской операцией: он срабатывает при подписке и может вызываться многократно. Запрос к серверу на каждом пикселе движения обычно не нужен.
const api = slider.noUiSlider;
api.set([20, 80]); // Установить две границы.
api.set([null, 70]); // Сохранить первую, изменить вторую.
const values = api.get(true); // Числа без format.
api.on('change.catalog', (formatted, handle, raw) => {
requestCatalog(raw);
});
api.off('.catalog'); // Снять обработчики этого пространства имён.
У одного ползунка с одной ручкой get(true) возвращает число, с несколькими — массив. Не пишите общий код так, будто результат всегда имеет одинаковую форму. Если одновременно подписаться на change и set, одно действие может привести к двум вызовам вашей логики; выбирайте событие по задаче.
Подробнее: события, аргументы обработчика и пространства имён.
Подробнее: get, set и чтение значений.
12. Числа, форматирование и отправка формы
Строка «1 500 ₽» удобна человеку, но неудобна вычислению. Храните число 1500, а валюту и разделители добавляйте при выводе. В обработчике третий аргумент unencoded содержит числовые значения; get(true) позволяет читать числа отдельно от настроенного format.
Если задаёте свой format, согласуйте to и from: одна функция оформляет значение, другая разбирает вход. Для экранного диктора можно задать отдельный ariaFormat. В нашем бронировании он превращает минуты в понятное время.
function readFiniteNumber(input) {
const text = input.value.trim();
if (text === '') return null; // Number('') иначе даст 0.
const value = Number(text);
return Number.isFinite(value) ? value : null;
}
// priceSlider уже создан и имеет две ручки.
form.addEventListener('submit', event => {
event.preventDefault();
const [minPrice, maxPrice] = priceSlider.noUiSlider.get(true);
const data = new FormData(form);
data.set('minPrice', String(minPrice));
data.set('maxPrice', String(maxPrice));
// Далее отправьте data своему API и обработайте ответ.
});
Элемент div с ползунком сам по себе не является успешным полем формы с именем. Используйте hidden-поля или явно заполните FormData, как выше. На сервере повторно проверяйте типы, диапазон, порядок границ и разрешённые варианты: клиентские ограничения можно обойти.
Не применяйте parseFloat к форматированной валюте: строка с пробелом может превратиться в неверное число. И не превращайте пустое поле в ноль незаметно для пользователя. В мастерской некорректный точный ввод сопровождается сообщением, а предыдущий корректный результат сохраняется.
Подробнее: format, tooltips и ariaFormat.
13. Сброс, изменение настроек и удаление компонента
reset() возвращает значения ползунка к исходным настройкам компонента. Он не знает о вашей выдаче, текстах ошибок, подтверждении брони или выбранном размере пакета. Поэтому полноценный сброс интерфейса должен восстанавливать собственную модель и связанные элементы.
function resetCatalog() {
priceSlider.noUiSlider.set([1000, 7000]);
feedback.textContent = '';
// Обработчик update восстановит поля, карточки и счётчик.
}
// Пример изменения поддерживаемых настроек:
slider.noUiSlider.updateOptions({
range: { min: 0, max: 200 },
step: 10
});
// Перед окончательным удалением компонента:
slider.noUiSlider.destroy();
Не все опции можно менять через updateOptions(). Например, изменение числа ручек требует пересоздания компонента. Сначала сохраните нужное состояние, вызовите destroy, затем создайте новый экземпляр. Не вызывайте create повторно на уже инициализированном элементе.
Во вкладках создавайте компонент, когда его контейнер готов к отображению. Следите, чтобы повторное открытие не добавляло ещё один набор обработчиков. Собственные события формы, наблюдатели и сетевые запросы тоже нужно очищать при удалении интерфейса: destroy библиотеки не управляет всем кодом приложения.
Подробнее: изменение настроек, сброс и destroy.
14. Частые ошибки и проверка удобства
Ручка не двигается до нужного значения
Проверьте шаг, минимум/максимум, margin, limit и padding. На нелинейной шкале шаг зависит от участка. Рядом с контролом объясните ограничения и оставьте точный ввод допустимого значения.
В поле одно число, а в результате другое
Вероятно, библиотека применила ограничения или округление. После set читайте фактическое значение через get(true) либо update. Если число изменилось, сообщите об этом; не считайте результат по исходному неверному вводу.
Время или деньги считаются неправильно
Отделите единицы модели от оформления. Минуты не равны строке HH:mm, индекс политики не равен числу дней, положение ручки не равно доле участка. Для денег используйте подходящую минимальную единицу и заранее определённое округление.
Запросы отправляются несколько раз
Проверьте число подписок, вызов update при подписке и одновременные change/set. Для поиска данных может понадобиться задержка или отмена предыдущего запроса; это логика вашего приложения.
Копирование не разрешено браузером
Используйте скачивание файла либо выделите видимый код и скопируйте вручную. Успешный статус должен появляться только после успешной записи в буфер обмена.
Нужны ли подсказки прямо над каждой ручкой?
Они удобны не всегда: у близких значений подписи могут пересекаться. Постоянный результат рядом с компонентом и подписанные поля часто читаются лучше. На узком экране проверьте крайние и почти одинаковые значения.
Перед внедрением проверьте мышь, Tab и стрелки, точный ввод, пустое поле, границы диапазона, сброс и самый длинный русский текст. На телефоне ползунок не должен лишать человека обычной прокрутки страницы. Важные значения и ошибки дублируйте текстом; одного цвета выделения недостаточно.
15. Источники и что попробовать дальше
Основные параметры и API сверены с официальной документацией. При переносе закрепляйте версию библиотеки, сохраняйте лицензию и проверяйте поведение на реальном сайте.
- noUiSlider: обзор и подключение.
- Диапазоны, шаги и нелинейные значения.
- Опции, ограничения и клавиатура.
- События и аргументы обработчиков.
- Форматирование и доступные подписи.
- Исходники и версия 15.8.1.
Ползунок часто работает вместе с другими элементами. Для выбора нескольких условий пригодится Tom Select, для форматированного ввода — IMask. Подход «сначала настроить компонент, затем проверить его в задаче» можно сравнить с NumberFlow и Kokonut UI.


