Используйте нативный ввод диапазона
Используйте элемент <input type="range"> с ярлыком, а не создавайте ползунок заново с помощью элементов <div> или специальных обработчиков указателя. Встроенный элемент управления сохраняет взаимодействие с клавиатурой и указателем, поведение при касании и поддержку специальных возможностей. Настройте min, max, step и value для своего варианта использования.
<label for="range-slider">Volume</label>
<input type="range" id="range-slider" value="70"/>
Если для значения требуется форматированный ярлык или единица измерения, укажите их в обычном контенте DOM и обновляйте aria-valuetext при изменении. Не используйте ::before или ::after в псевдоэлементах ползунка, так как сгенерированный контент в элементах управления формой несовместим. Если требуется подсказка, которая следует за ползунком, привяжите ее к ползунку с помощью позиционирования привязки CSS. См. Подсказки с учетом положения для подсказок, которые сохраняют правильную ориентацию при переворачивании.
Выберите подход к стилизации
Для простой настройки цвета используйте формы в фирменном стиле и сохраните нативную отрисовку браузера:
input[type="range"] {
accent-color: var(--brand-color);
}
accent-color не является полным API для стилизации ползунка. Его влияние на ползунок, дорожку и заполнение зависит от агента пользователя. Если вам нужно настроить дорожку, ползунок, размеры, форму или заливку, используйте псевдоэлементы, перечисленные ниже.
Настройте стиль дорожки и ползунка
Сбросьте стили ОС по умолчанию с помощью appearance: none, margin: 0 и border: 0. Чтобы нормализовать межбраузерную отрисовку, объявите псевдоэлементы WebKit и Firefox в отдельных блоках правил и отцентрируйте ползунок WebKit с помощью margin-block-start: calc((var(--slider-track-size) - var(--slider-thumb-size)) / 2) (Firefox центрирует ползунок автоматически). Сохраняйте потребительские значения в качестве дополнительных параметров во входных данных, чтобы темы не были нацелены на псевдоэлементы напрямую.
input[type="range"] {
--slider-track-size: 0.5rem;
--slider-thumb-size: 1.25rem;
--slider-track-radius: 999px;
--slider-thumb-radius: 50%;
--slider-track-color: #d9d9d9;
--slider-fill-color: #06c;
--slider-thumb-color: var(--slider-fill-color);
--slider-direction: to right;
/* reverse gradient direction for right-to-left layouts */
&:dir(rtl) {
--slider-direction: to left;
}
/* Read min and max from attributes; --control-value is synced by the script below. */
--attr-min: attr(min type(<number>), 0);
--attr-max: attr(max type(<number>), 100);
--control-value: attr(value type(<number>), 50);
--slider-progress: calc(
progress(var(--control-value), var(--attr-min), var(--attr-max)) * 100%
);
appearance: none;
inline-size: 100%;
block-size: 2.5rem; /* Preserve a generous interaction area. */
margin: 0;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
cursor: pointer;
}
/* WebKit/Blink. */
input[type="range"]::-webkit-slider-runnable-track {
block-size: var(--slider-track-size);
border: 0;
border-radius: var(--slider-track-radius);
background: linear-gradient(
var(--slider-direction),
var(--slider-fill-color) var(--slider-progress),
var(--slider-track-color) var(--slider-progress)
);
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
inline-size: var(--slider-thumb-size);
block-size: var(--slider-thumb-size);
margin-block-start: calc(
(var(--slider-track-size) - var(--slider-thumb-size)) / 2
);
border: 0;
border-radius: var(--slider-thumb-radius);
background: var(--slider-thumb-color);
}
/* Firefox. */
input[type="range"]::-moz-range-track {
block-size: var(--slider-track-size);
border: 0;
border-radius: var(--slider-track-radius);
background: var(--slider-track-color);
}
input[type="range"]::-moz-range-progress {
block-size: var(--slider-track-size);
border-radius: var(--slider-track-radius);
background: var(--slider-fill-color);
}
input[type="range"]::-moz-range-thumb {
inline-size: var(--slider-thumb-size);
block-size: var(--slider-thumb-size);
border: 0;
border-radius: var(--slider-thumb-radius);
background: var(--slider-thumb-color);
}
Если вы удалили стандартный индикатор фокуса клавиатуры, обязательно добавьте видимый индикатор. Не используйте только цвет.
input[type="range"]:focus-visible {
outline: 2px solid var(--slider-fill-color);
outline-offset: 4px;
}
Настройте стиль активного трека
Если заполненная часть дорожки оформлена иначе, чем незаполненная, Firefox предоставляет ее через ::-moz-range-progress. В WebKit/Blink нет эквивалентного псевдоэлемента, поэтому синхронизируйте значение ввода с --control-value в событиях input:
const slider = document.querySelector('#range-slider');
function syncSliderValue() {
slider.style.setProperty('--control-value', slider.value);
}
syncSliderValue();
slider.addEventListener('input', syncSliderValue);
Ограничения
- Не объединяйте псевдоселекторы WebKit и Firefox в один список, разделенный запятыми (например,
::-webkit-slider-thumb, ::-moz-range-thumb). Браузеры отбрасывают все правило, если обнаруживают нераспознанный псевдоэлемент поставщика.
Резервные объявления
Резервные варианты и поддержка свойства accent-color в браузерах
Свойство accent-color – это прогрессивное улучшение.
Браузеры, которые не поддерживают это свойство, будут игнорировать его и использовать цвета интерфейса по умолчанию.
Резервные объявления и поддержка браузеров для progress() и attr()
Если progress() не поддерживается, вычислите --slider-progress с помощью calc():
@supports not (opacity: progress(1, 0, 100)) {
input[type="range"] {
--slider-progress: calc(
(var(--control-value) - var(--attr-min)) /
(var(--attr-max) - var(--attr-min)) * 100%
);
}
}
Если тип attr() не поддерживается, синхронизируйте --attr-min и --attr-max с атрибутами min и max в JavaScript:
function syncSliderValue() {
slider.style.setProperty('--attr-min', slider.min || 0);
slider.style.setProperty('--attr-max', slider.max || 100);
slider.style.setProperty('--control-value', slider.value);
}