品牌一致的范围滑块

使用原生范围输入

使用带标签的 <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 伪元素,并使用 margin-block-start: calc((var(--slider-track-size) - var(--slider-thumb-size)) / 2) 将 WebKit 滑块居中(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 不提供等效的伪元素,因此请在 input 事件中将实时输入值同步到 --control-value:

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() 不受支持,则使用 calc() 计算 --slider-progress:

@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(),请在 JavaScript 中通过输入的 min 和 max 属性同步 --attr-min 和 --attr-max:

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);
}