【问题标题】:HTML5: Slider with two inputs possible?HTML5:可能有两个输入的滑块?
【发布时间】:2011-06-12 20:12:12
【问题描述】:

是否可以制作带有两个输入值的 HTML5 滑块,例如选择价格范围?如果可以,怎么做?

【问题讨论】:

  • 我为此制作了一个基于 CSS 的组件 - Codepen demo
  • 到目前为止,在所有这些答案中,我相信只有一个是可访问的,而另一个是 有点 可访问的,尽管我已经评论了该答案的可访问性问题。如果你正在阅读这篇文章,那么现在至少是 2022 年了,我恳请你找到一个完全可访问的解决方案 (ctrl+f "accessibility")

标签: forms html slider


【解决方案1】:

2022 - 无障碍解决方案 - 实施 30 秒解决方案

此解决方案基于 this answer by @JoostS。可访问性是所有答案都没有关注的问题,这是一个问题,因此我在上述答案的基础上构建了它,使其更易于访问和可扩展,因为它存在一些缺陷。

用法很简单:

  1. 使用CDN 或在本地托管脚本:https://cdn.jsdelivr.net/gh/maxshuty/accessible-web-components/dist/simpleRange.min.js
  2. 将此元素添加到您的模板或 HTML:<range-selector min-range="0" max-range="1000" />
  3. 通过监听 range-changed 事件(或您传入的任何 event-name-to-emit-on-change)来连接它

就是这样。 View the full demo here

这是一个小提琴:

window.addEventListener('range-changed', (e) => {console.log(`Range changed for: ${e.detail.sliderId}. Min/Max range values are available in this object too`)})
<script src="https://cdn.jsdelivr.net/gh/maxshuty/accessible-web-components/dist/simpleRange.min.js"></script>

<div>
  <range-selector
    id="rangeSelector1"
    min-label="Minimum"
    max-label="Maximum"
    min-range="1000"
    max-range="2022"
    number-of-legend-items-to-show="6"
  />
</div>

<div>
  <range-selector
    id="rangeSelector2"
    min-label="Minimum"
    max-label="Maximum"
    min-range="1000"
    max-range="2022"
    number-of-legend-items-to-show="3"
    slider-color="#6b5b95"
  />
</div>

<div>
  <range-selector
    id="rangeSelector3"
    min-label="Minimum"
    max-label="Maximum"
    min-range="1000"
    max-range="2022"
    hide-label
    hide-legend
  />
</div>

我决定解决链接答案的问题,例如使用 display: none 的标签(对 a11y 不利)、滑块上没有视觉焦点等,并通过清理事件侦听器并改进代码来改进代码动态且可扩展。

我创建了这个tiny 库,其中包含许多选项来自定义颜色、事件名称、轻松挂钩、使可访问的标签 i18n 支持等等。 Here it is in a fiddle如果你想玩的话。

您可以轻松自定义它显示的图例项的数量,隐藏或显示标签和图例,以及自定义所有内容的颜色,包括像这样的焦点颜色。

使用几个道具的例子:

<range-selector
  min-label="i18n Minimum Range"
  max-label="i18n Maximum Range"
  min-range="5"
  max-range="555"
  number-of-legend-items-to-show="6"
  event-name-to-emit-on-change="my-custom-range-changed-event"
  slider-color="orange"
  circle-color="#f7cac9"
  circle-border-color="#083535"
  circle-focus-border-color="#3ec400"
/>

然后在你的脚本中:

window.addEventListener('my-custom-range-changed-event', (e) => { const data = e.detail; });

最后,如果你发现这缺少你需要的东西,我可以很容易地自定义这个库。

只需复制this file,您就可以在顶部看到cssHelpersconstants 对象,其中包含您可能希望进一步自定义的大部分变量。

自从我使用 Native Web Component 构建它以来,我利用了 disconnectedCallback 和其他钩子来清理事件侦听器并进行设置。

【讨论】:

  • 干得好!我喜欢它。
【解决方案2】:

此代码涵盖以下几点

  1. 使用 HTML、CSS、JS 的双滑块

  2. 我已经使用嵌入式 ruby​​ 修改了这个滑块,因此我们可以使用 rails 中的参数保存以前应用的值。

     <% left_width = params[:min].nil? ? 0 : ((params[:min].to_f/100000) * 100).to_i %>
     <% left_value = params[:min].nil? ? '0' : params[:min] %>
     <% right_width = params[:max].nil? ? 100 : ((params[:max].to_f/100000) * 100).to_i %>
     <% right_value = params[:max].nil? ? '100000' : params[:max] %>
    
     <div class="range-slider-outer">
       <div slider id="slider-distance">
         <div class="slider-inner">
           <div inverse-left style="width:<%= left_width %>%;"></div>
           <div inverse-right style="width:<%= 100 - right_width %>%;"></div>
           <div range style="left:<%= left_width %>%;right:<%= 100 - right_width %>%;"></div>
           <span thumb style="left:<%= left_width %>%;"></span>
           <span thumb style="left:<%= right_width %>%;"></span>
           <div sign style="">
             Rs.<span id="value"><%= left_value.to_i %></span> to
           </div>
           <div sign style="">
             Rs.<span id="value"><%= right_value.to_i %></span>
           </div>
         </div>
    
         <input type="range" name="min" value=<%= left_value %> max="100000" min="0" step="100" oninput="
         this.value=Math.min(this.value,this.parentNode.childNodes[5].value-1);
         let value = (this.value/parseInt(this.max))*100
         var children = this.parentNode.childNodes[1].childNodes;
         children[1].style.width=value+'%';
         children[5].style.left=value+'%';
         children[7].style.left=value+'%';children[11].style.left=value+'%';
         children[11].childNodes[1].innerHTML=this.value;" />
    
         <input type="range" name="max" value=<%= right_value %> max="100000" min="0" step="100" oninput="
         this.value=Math.max(this.value,this.parentNode.childNodes[3].value-(-1));
         let value = (this.value/parseInt(this.max))*100
         var children = this.parentNode.childNodes[1].childNodes;
         children[3].style.width=(100-value)+'%';
         children[5].style.right=(100-value)+'%';
         children[9].style.left=value+'%';children[13].style.left=value+'%';
         children[13].childNodes[1].innerHTML=this.value;" />
       </div>
       <div class="range-label">
         <div>0</div>
         <div>100000</div>
       </div>
     </div>
    

[slider] {
  /*width: 300px;*/
  position: relative;
  height: 5px;
  /*margin: 20px auto;*/
  /* height: 100%; */
}
[slider] > div {
  position: absolute;
  left: 13px;
  right: 15px;
  height: 14px;
  top: 5px;
}
[slider] > div > [inverse-left] {
  position: absolute;
  left: 0;
  height: 14px;
  border-radius: 3px;
  background-color: #CCC;
  /*margin: 0 7px;*/
  margin: 0 -7px;
}
[slider] > div > [inverse-right] {
  position: absolute;
  right: 0;
  height: 14px;
  border-radius: 3px;
  background-color: #CCC;
  /*margin: 0 7px;*/
  margin: 0 -7px;
}
[slider] > div > [range] {
  position: absolute;
  left: 0;
  height: 14px;
  border-radius: 14px;
  background-color:#8950fc;
}
[slider] > div > [thumb] {
  position: absolute;
  top: -3px;
  z-index: 2;
  height: 20px;
  width: 20px;
  text-align: left;
  margin-left: -11px;
  cursor: pointer;
  /* box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4); */
  background-color: #FFF;
  /*border-radius: 50%;*/
  border-radius:2px;
  outline: none;
}
[slider] > input[type=range] {
  position: absolute;
  pointer-events: none;
  -webkit-appearance: none;
  z-index: 3;
  height: 14px;
  top: -2px;
  width: 100%;
  opacity: 0;
}
div[slider] > input[type=range]:focus::-webkit-slider-runnable-track {
  background: transparent;
  border: transparent;
}
div[slider] > input[type=range]:focus {
  outline: none;
}
div[slider] > input[type=range]::-webkit-slider-thumb {
  pointer-events: all;
  width: 28px;
  height: 28px;
  border-radius: 0px;
  border: 0 none;
  background: red;
  -webkit-appearance: none;
}
div[slider] > input[type=range]::-ms-fill-lower {
  background: transparent;
  border: 0 none;
}
div[slider] > input[type=range]::-ms-fill-upper {
  background: transparent;
  border: 0 none;
}
div[slider] > input[type=range]::-ms-tooltip {
  display: none;
}
[slider] > div > [sign] {
 /* opacity: 0;
  position: absolute;
  margin-left: -11px;
  top: -39px;
  z-index:3;
  background-color:#1a243a;
  color: #fff;
  width: 28px;
  height: 28px;
  border-radius: 28px;
  -webkit-border-radius: 28px;
  align-items: center;
  -webkit-justify-content: center;
  justify-content: center;
  text-align: center;*/
    color: #A5B2CB;
    border-radius: 28px;
    justify-content: center;
    text-align: center;
    display: inline-block;
    margin-top: 12px;
    font-size: 14px;
    font-weight: bold;
}
.slider-inner{
  text-align:center;
}
/*[slider] > div > [sign]:after {
  position: absolute;
  content: '';
  left: 0;
  border-radius: 16px;
  top: 19px;
  border-left: 14px solid transparent;
  border-right: 14px solid transparent;
  border-top-width: 16px;
  border-top-style: solid;
  border-top-color:#1a243a;
}*/
[slider] > div > [sign] > span {
  font-size: 12px;
  font-weight: 700;
  line-height: 28px;
}
[slider]:hover > div > [sign] {
  opacity: 1;
}
.range-label{
  display: flex;
  justify-content: space-between;
  margin-top: 28px;
  padding: 0px 5px;
}
.range-slider-outer{
  width:calc(100% - 20px);
  margin:auto;
  margin-bottom: 10px;
  margin-top: 10px;
}

【讨论】:

    【解决方案3】:

    问题是:“是否可以制作具有两个输入值的 HTML5 滑块,例如选择价格范围?如果可以,怎么做?”

    在 2020 年,可以针对价格范围创建一个具有两个拇指的完全可访问、原生、非 jquery HTML5 滑块。如果在我创建了这个解决方案之后发现了这个帖子,并且我认为在这里分享我的实现会很好。

    此实现已在移动 Chrome 和 Firefox (Android) 以及 Chrome 和 Firefox (Linux) 上进行了测试。我不确定其他平台,但它应该相当不错。我很想得到您的反馈并改进此解决方案。

    此解决方案允许在一个页面上显示多个实例,并且它仅包含两个输入(每个输入),并带有用于屏幕阅读器的描述性标签。您可以在网格标签的数量中设置拇指大小。此外,您可以使用触摸、键盘和鼠标与滑块进行交互。由于 'on input' 事件监听器,值在调整期间更新。

    我的第一种方法是覆盖滑块并剪辑它们。然而,这导致了具有大量浏览器依赖项的复杂代码。然后我用两个“内联”滑块重新创建了解决方案。这是您将在下面找到的解决方案。

    var thumbsize = 14;
    
    function draw(slider,splitvalue) {
    
        /* set function vars */
        var min = slider.querySelector('.min');
        var max = slider.querySelector('.max');
        var lower = slider.querySelector('.lower');
        var upper = slider.querySelector('.upper');
        var legend = slider.querySelector('.legend');
        var thumbsize = parseInt(slider.getAttribute('data-thumbsize'));
        var rangewidth = parseInt(slider.getAttribute('data-rangewidth'));
        var rangemin = parseInt(slider.getAttribute('data-rangemin'));
        var rangemax = parseInt(slider.getAttribute('data-rangemax'));
    
        /* set min and max attributes */
        min.setAttribute('max',splitvalue);
        max.setAttribute('min',splitvalue);
    
        /* set css */
        min.style.width = parseInt(thumbsize + ((splitvalue - rangemin)/(rangemax - rangemin))*(rangewidth - (2*thumbsize)))+'px';
        max.style.width = parseInt(thumbsize + ((rangemax - splitvalue)/(rangemax - rangemin))*(rangewidth - (2*thumbsize)))+'px';
        min.style.left = '0px';
        max.style.left = parseInt(min.style.width)+'px';
        min.style.top = lower.offsetHeight+'px';
        max.style.top = lower.offsetHeight+'px';
        legend.style.marginTop = min.offsetHeight+'px';
        slider.style.height = (lower.offsetHeight + min.offsetHeight + legend.offsetHeight)+'px';
        
        /* correct for 1 off at the end */
        if(max.value>(rangemax - 1)) max.setAttribute('data-value',rangemax);
    
        /* write value and labels */
        max.value = max.getAttribute('data-value'); 
        min.value = min.getAttribute('data-value');
        lower.innerHTML = min.getAttribute('data-value');
        upper.innerHTML = max.getAttribute('data-value');
    
    }
    
    function init(slider) {
        /* set function vars */
        var min = slider.querySelector('.min');
        var max = slider.querySelector('.max');
        var rangemin = parseInt(min.getAttribute('min'));
        var rangemax = parseInt(max.getAttribute('max'));
        var avgvalue = (rangemin + rangemax)/2;
        var legendnum = slider.getAttribute('data-legendnum');
    
        /* set data-values */
        min.setAttribute('data-value',rangemin);
        max.setAttribute('data-value',rangemax);
        
        /* set data vars */
        slider.setAttribute('data-rangemin',rangemin); 
        slider.setAttribute('data-rangemax',rangemax); 
        slider.setAttribute('data-thumbsize',thumbsize); 
        slider.setAttribute('data-rangewidth',slider.offsetWidth);
    
        /* write labels */
        var lower = document.createElement('span');
        var upper = document.createElement('span');
        lower.classList.add('lower','value');
        upper.classList.add('upper','value');
        lower.appendChild(document.createTextNode(rangemin));
        upper.appendChild(document.createTextNode(rangemax));
        slider.insertBefore(lower,min.previousElementSibling);
        slider.insertBefore(upper,min.previousElementSibling);
        
        /* write legend */
        var legend = document.createElement('div');
        legend.classList.add('legend');
        var legendvalues = [];
        for (var i = 0; i < legendnum; i++) {
            legendvalues[i] = document.createElement('div');
            var val = Math.round(rangemin+(i/(legendnum-1))*(rangemax - rangemin));
            legendvalues[i].appendChild(document.createTextNode(val));
            legend.appendChild(legendvalues[i]);
    
        } 
        slider.appendChild(legend);
    
        /* draw */
        draw(slider,avgvalue);
    
        /* events */
        min.addEventListener("input", function() {update(min);});
        max.addEventListener("input", function() {update(max);});
    }
    
    function update(el){
        /* set function vars */
        var slider = el.parentElement;
        var min = slider.querySelector('#min');
        var max = slider.querySelector('#max');
        var minvalue = Math.floor(min.value);
        var maxvalue = Math.floor(max.value);
        
        /* set inactive values before draw */
        min.setAttribute('data-value',minvalue);
        max.setAttribute('data-value',maxvalue);
    
        var avgvalue = (minvalue + maxvalue)/2;
    
        /* draw */
        draw(slider,avgvalue);
    }
    
    var sliders = document.querySelectorAll('.min-max-slider');
    sliders.forEach( function(slider) {
        init(slider);
    });
    * {padding: 0; margin: 0;}
    body {padding: 40px;}
    
    .min-max-slider {position: relative; width: 200px; text-align: center; margin-bottom: 50px;}
    .min-max-slider > label {display: none;}
    span.value {height: 1.7em; font-weight: bold; display: inline-block;}
    span.value.lower::before {content: "€"; display: inline-block;}
    span.value.upper::before {content: "- €"; display: inline-block; margin-left: 0.4em;}
    .min-max-slider > .legend {display: flex; justify-content: space-between;}
    .min-max-slider > .legend > * {font-size: small; opacity: 0.25;}
    .min-max-slider > input {cursor: pointer; position: absolute;}
    
    /* webkit specific styling */
    .min-max-slider > input {
      -webkit-appearance: none;
      outline: none!important;
      background: transparent;
      background-image: linear-gradient(to bottom, transparent 0%, transparent 30%, silver 30%, silver 60%, transparent 60%, transparent 100%);
    }
    .min-max-slider > input::-webkit-slider-thumb {
      -webkit-appearance: none; /* Override default look */
      appearance: none;
      width: 14px; /* Set a specific slider handle width */
      height: 14px; /* Slider handle height */
      background: #eee; /* Green background */
      cursor: pointer; /* Cursor on hover */
      border: 1px solid gray;
      border-radius: 100%;
    }
    .min-max-slider > input::-webkit-slider-runnable-track {cursor: pointer;}
    <div class="min-max-slider" data-legendnum="2">
        <label for="min">Minimum price</label>
        <input id="min" class="min" name="min" type="range" step="1" min="0" max="3000" />
        <label for="max">Maximum price</label>
        <input id="max" class="max" name="max" type="range" step="1" min="0" max="3000" />
    </div>

    请注意,您应该将步长保持为 1,以防止由于重绘/重绘错误而更改值。

    在线查看:https://codepen.io/joosts/pen/rNLdxvK

    【讨论】:

    • 谢谢,我真的很喜欢这个解决方案!
    • 我在舍入时遇到了问题(avgvalue 可以是 XX.5)。因此,您可以使用左滑块创建最小尺寸 1 的范围,但使用右滑块创建 0 的范围。我已经用floor/ceil 解决了这个问题,相关输入的max/min + 条件padding-left 用于第二个滑块,因此允许两侧的最小尺寸范围为1。
    • 这是一个聪明的代码,但我不会说“时代变了”,这仍然是使用两个滑块,仍然添加 JS 和 Css 来克服标准的缺点。在我看来,“更改时间”将是: 以支持多值输入元素。什么的。
    • 我同意这个解决方案,但是当我尝试使用 javascript 更新值时遇到问题。谁能帮我动态更新滑块?
    • 喜欢这大部分可访问,我认为唯一应该做的就是添加轮廓、颜色更改或其他一些指示符以使其更易于访问用户在视觉上知道他们正在调整幻灯片的任一侧。这应该发生在焦点上,以便在 Tab 键和使用箭头键时也能正常工作。
    【解决方案4】:

    当然,您可以简单地使用两个相互重叠的滑块并添加一些 javascript(实际上不超过 5 行),以使选择器不超过最小/最大值(就像在 @Garys 中一样)解决方案。

    附上你会发现一个简短的 sn-p 改编自当前项目,包括一些 CSS3 样式来展示你可以做什么(仅限 webkit)。我还添加了一些标签来显示选定的值。

    它使用 JQuery,但 vanillajs 版本并不神奇。

    @Update: 下面的代码只是一个概念证明。由于许多请求,我为 Mozilla Firefox 添加了一个可能的解决方案(不更改原始代码)。您可能需要在使用之前对下面的代码进行折射。

        (function() {
    
            function addSeparator(nStr) {
                nStr += '';
                var x = nStr.split('.');
                var x1 = x[0];
                var x2 = x.length > 1 ? '.' + x[1] : '';
                var rgx = /(\d+)(\d{3})/;
                while (rgx.test(x1)) {
                    x1 = x1.replace(rgx, '$1' + '.' + '$2');
                }
                return x1 + x2;
            }
    
            function rangeInputChangeEventHandler(e){
                var rangeGroup = $(this).attr('name'),
                    minBtn = $(this).parent().children('.min'),
                    maxBtn = $(this).parent().children('.max'),
                    range_min = $(this).parent().children('.range_min'),
                    range_max = $(this).parent().children('.range_max'),
                    minVal = parseInt($(minBtn).val()),
                    maxVal = parseInt($(maxBtn).val()),
                    origin = $(this).context.className;
    
                if(origin === 'min' && minVal > maxVal-5){
                    $(minBtn).val(maxVal-5);
                }
                var minVal = parseInt($(minBtn).val());
                $(range_min).html(addSeparator(minVal*1000) + ' €');
    
    
                if(origin === 'max' && maxVal-5 < minVal){
                    $(maxBtn).val(5+ minVal);
                }
                var maxVal = parseInt($(maxBtn).val());
                $(range_max).html(addSeparator(maxVal*1000) + ' €');
            }
    
         $('input[type="range"]').on( 'input', rangeInputChangeEventHandler);
    })();
    body{
    font-family: sans-serif;
    font-size:14px;
    }
    input[type='range'] {
      width: 210px;
      height: 30px;
      overflow: hidden;
      cursor: pointer;
        outline: none;
    }
    input[type='range'],
    input[type='range']::-webkit-slider-runnable-track,
    input[type='range']::-webkit-slider-thumb {
      -webkit-appearance: none;
        background: none;
    }
    input[type='range']::-webkit-slider-runnable-track {
      width: 200px;
      height: 1px;
      background: #003D7C;
    }
    
    input[type='range']:nth-child(2)::-webkit-slider-runnable-track{
      background: none;
    }
    
    input[type='range']::-webkit-slider-thumb {
      position: relative;
      height: 15px;
      width: 15px;
      margin-top: -7px;
      background: #fff;
      border: 1px solid #003D7C;
      border-radius: 25px;
      z-index: 1;
    }
    
    
    input[type='range']:nth-child(1)::-webkit-slider-thumb{
      z-index: 2;
    }
    
    .rangeslider{
        position: relative;
        height: 60px;
        width: 210px;
        display: inline-block;
        margin-top: -5px;
        margin-left: 20px;
    }
    .rangeslider input{
        position: absolute;
    }
    .rangeslider{
        position: absolute;
    }
    
    .rangeslider span{
        position: absolute;
        margin-top: 30px;
        left: 0;
    }
    
    .rangeslider .right{
       position: relative;
       float: right;
       margin-right: -5px;
    }
    
    
    /* Proof of concept for Firefox */
    @-moz-document url-prefix() {
      .rangeslider::before{
        content:'';
        width:100%;
        height:2px;
        background: #003D7C;
        display:block;
        position: relative;
        top:16px;
      }
    
      input[type='range']:nth-child(1){
        position:absolute;
        top:35px !important;
        overflow:visible !important;
        height:0;
      }
    
      input[type='range']:nth-child(2){
        position:absolute;
        top:35px !important;
        overflow:visible !important;
        height:0;
      }
    input[type='range']::-moz-range-thumb {
      position: relative;
      height: 15px;
      width: 15px;
      margin-top: -7px;
      background: #fff;
      border: 1px solid #003D7C;
      border-radius: 25px;
      z-index: 1;
    }
    
      input[type='range']:nth-child(1)::-moz-range-thumb {
          transform: translateY(-20px);    
      }
      input[type='range']:nth-child(2)::-moz-range-thumb {
          transform: translateY(-20px);    
      }
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <div class="rangeslider">
                                    <input class="min" name="range_1" type="range" min="1" max="100" value="10" />
                                    <input class="max" name="range_1" type="range" min="1" max="100" value="90" />
                                    <span class="range_min light left">10.000 €</span>
                                    <span class="range_max light right">90.000 €</span>
                                </div>

    【讨论】:

    • 嘿,看起来棒极了!但它在 Firefox 中不起作用,您只能拖动最大输入。你解决了吗?
    • 天哪。我来这里是为了添加几乎完全相同的东西! simple.gy/blog/range-slider-two-handles我的版本将输入并排放置,但也使用双输入。
    • 我现在为 Firefox 添加了一个概念验证
    • 您好!我发现这很有用,并希望为将来的其他人阅读做出贡献。从 jQuery 3.0 开始,这不再有效。 origin = $(this).context.className; 行应更改为 origin = e.originalEvent.target.className; 或等效项。 .context 功能在 1.10 中已弃用,并在 3.0 中删除
    【解决方案5】:

    不,HTML5 range input 只接受一个输入。我建议您使用类似 jQuery UI range slider 的东西来完成该任务。

    【讨论】:

    • 感谢您的链接和信息。我必须检查我是否可以让它在移动设备上运行。
    • 前段时间......但我设法通过将两个滑块完全放在彼此之上来“伪造”一个双滑块。一个从最小值开始,另一个从最大值开始。我想那是作弊,但……它对我有用。
    • WhatWG 至少在讨论实施它:html.spec.whatwg.org/multipage/…
    • 我自己比 jQuery UI 滑块更喜欢 ionRangeSlider:ionden.com/a/plugins/ion.rangeSlider/en.html
    • 另一种方法是使用并排输入控件“伪造”双滑块:simple.gy/blog/range-slider-two-handles
    【解决方案6】:

    其实我直接在html中使用了我的脚本。但是在 javascript 中,当您为此事件添加 oninput 事件侦听器时,它会自动提供数据。您只需要根据您的要求分配值。

    [slider] {
      width: 300px;
      position: relative;
      height: 5px;
      margin: 45px 0 10px 0;
    }
    
    [slider] > div {
      position: absolute;
      left: 13px;
      right: 15px;
      height: 5px;
    }
    [slider] > div > [inverse-left] {
      position: absolute;
      left: 0;
      height: 5px;
      border-radius: 10px;
      background-color: #CCC;
      margin: 0 7px;
    }
    
    [slider] > div > [inverse-right] {
      position: absolute;
      right: 0;
      height: 5px;
      border-radius: 10px;
      background-color: #CCC;
      margin: 0 7px;
    }
    
    
    [slider] > div > [range] {
      position: absolute;
      left: 0;
      height: 5px;
      border-radius: 14px;
      background-color: #d02128;
    }
    
    [slider] > div > [thumb] {
      position: absolute;
      top: -7px;
      z-index: 2;
      height: 20px;
      width: 20px;
      text-align: left;
      margin-left: -11px;
      cursor: pointer;
      box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
      background-color: #FFF;
      border-radius: 50%;
      outline: none;
    }
    
    [slider] > input[type=range] {
      position: absolute;
      pointer-events: none;
      -webkit-appearance: none;
      z-index: 3;
      height: 14px;
      top: -2px;
      width: 100%;
      opacity: 0;
    }
    
    div[slider] > input[type=range]:focus::-webkit-slider-runnable-track {
      background: transparent;
      border: transparent;
    }
    
    div[slider] > input[type=range]:focus {
      outline: none;
    }
    
    div[slider] > input[type=range]::-webkit-slider-thumb {
      pointer-events: all;
      width: 28px;
      height: 28px;
      border-radius: 0px;
      border: 0 none;
      background: red;
      -webkit-appearance: none;
    }
    
    div[slider] > input[type=range]::-ms-fill-lower {
      background: transparent;
      border: 0 none;
    }
    
    div[slider] > input[type=range]::-ms-fill-upper {
      background: transparent;
      border: 0 none;
    }
    
    div[slider] > input[type=range]::-ms-tooltip {
      display: none;
    }
    
    [slider] > div > [sign] {
      opacity: 0;
      position: absolute;
      margin-left: -11px;
      top: -39px;
      z-index:3;
      background-color: #d02128;
      color: #fff;
      width: 28px;
      height: 28px;
      border-radius: 28px;
      -webkit-border-radius: 28px;
      align-items: center;
      -webkit-justify-content: center;
      justify-content: center;
      text-align: center;
    }
    
    [slider] > div > [sign]:after {
      position: absolute;
      content: '';
      left: 0;
      border-radius: 16px;
      top: 19px;
      border-left: 14px solid transparent;
      border-right: 14px solid transparent;
      border-top-width: 16px;
      border-top-style: solid;
      border-top-color: #d02128;
    }
    
    [slider] > div > [sign] > span {
      font-size: 12px;
      font-weight: 700;
      line-height: 28px;
    }
    
    [slider]:hover > div > [sign] {
      opacity: 1;
    }
    <div slider id="slider-distance">
      <div>
        <div inverse-left style="width:70%;"></div>
        <div inverse-right style="width:70%;"></div>
        <div range style="left:0%;right:0%;"></div>
        <span thumb style="left:0%;"></span>
        <span thumb style="left:100%;"></span>
        <div sign style="left:0%;">
          <span id="value">0</span>
        </div>
        <div sign style="left:100%;">
          <span id="value">100</span>
        </div>
      </div>
      <input type="range" value="0" max="100" min="0" step="1" oninput="
      this.value=Math.min(this.value,this.parentNode.childNodes[5].value-1);
      let value = (this.value/parseInt(this.max))*100
      var children = this.parentNode.childNodes[1].childNodes;
      children[1].style.width=value+'%';
      children[5].style.left=value+'%';
      children[7].style.left=value+'%';children[11].style.left=value+'%';
      children[11].childNodes[1].innerHTML=this.value;" />
    
      <input type="range" value="100" max="100" min="0" step="1" oninput="
      this.value=Math.max(this.value,this.parentNode.childNodes[3].value-(-1));
      let value = (this.value/parseInt(this.max))*100
      var children = this.parentNode.childNodes[1].childNodes;
      children[3].style.width=(100-value)+'%';
      children[5].style.right=(100-value)+'%';
      children[9].style.left=value+'%';children[13].style.left=value+'%';
      children[13].childNodes[1].innerHTML=this.value;" />
    </div>

    【讨论】:

    • 你是个天才!这是个好主意,而且你的造型也很棒。
    • 我一直在寻找几天 - 这是一个很好的解决方案!谢谢分享!!
    【解决方案7】:

    来晚了,但noUiSlider 避免了 jQuery-ui 依赖项,而接受的答案没有。它唯一的“警告”是 IE 支持适用于 IE9 和更新版本,如果旧版 IE 不适合您。

    它也是免费的、开源的,可以不受限制地用于商业项目。

    安装:下载 noUiSlider,将 CSS 和 JS 文件提取到站点文件系统的某个位置,然后从 head 链接到 CSS,从 body 链接到 JS:

    <!-- In <head> -->
    <link href="nouislider.min.css" rel="stylesheet">
    
    <!-- In <body> -->
    <script src="nouislider.min.js"></script>
    

    示例用法:创建一个从 0 到 100 的滑块,并开始设置为 20-80。

    HTML:

    <div id="slider">
    </div>
    

    JS:

    var slider = document.getElementById('slider');
    
    noUiSlider.create(slider, {
        start: [20, 80],
        connect: true,
        range: {
            'min': 0,
            'max': 100
        }
    });
    

    【讨论】:

    • 哇,太棒了!!这正是我们所需要的,而且开发得非常好! WHITOUT jQuery
    • 自己添加它并向项目发送拉取请求应该相当容易?
    • 我没有深入研究它,但我可以将滑块与键盘一起使用,所以我认为它现在已经实现了@ptrin :)
    • 非常感谢您的精彩回答。事不宜迟,只要找到答案就分享。
    • @ChrisDixon(抱歉,刚刚看到评论)这应该足够了,也许尝试调试工具提示并确认它们已损坏。如果你能修复它们,你可以向项目发送 PR ;)
    【解决方案8】:

    一段时间以来,我一直在寻找一个轻量级、无依赖的双滑块(为此导入 jQuery 似乎很疯狂),但似乎没有很多。最后我稍微修改了@Wildhoney's code,真的很喜欢。

    function getVals(){
      // Get slider values
      var parent = this.parentNode;
      var slides = parent.getElementsByTagName("input");
        var slide1 = parseFloat( slides[0].value );
        var slide2 = parseFloat( slides[1].value );
      // Neither slider will clip the other, so make sure we determine which is larger
      if( slide1 > slide2 ){ var tmp = slide2; slide2 = slide1; slide1 = tmp; }
      
      var displayElement = parent.getElementsByClassName("rangeValues")[0];
          displayElement.innerHTML = slide1 + " - " + slide2;
    }
    
    window.onload = function(){
      // Initialize Sliders
      var sliderSections = document.getElementsByClassName("range-slider");
          for( var x = 0; x < sliderSections.length; x++ ){
            var sliders = sliderSections[x].getElementsByTagName("input");
            for( var y = 0; y < sliders.length; y++ ){
              if( sliders[y].type ==="range" ){
                sliders[y].oninput = getVals;
                // Manually trigger event first time to display values
                sliders[y].oninput();
              }
            }
          }
    }
      section.range-slider {
        position: relative;
        width: 200px;
        height: 35px;
        text-align: center;
    }
    
    section.range-slider input {
        pointer-events: none;
        position: absolute;
        overflow: hidden;
        left: 0;
        top: 15px;
        width: 200px;
        outline: none;
        height: 18px;
        margin: 0;
        padding: 0;
    }
    
    section.range-slider input::-webkit-slider-thumb {
        pointer-events: all;
        position: relative;
        z-index: 1;
        outline: 0;
    }
    
    section.range-slider input::-moz-range-thumb {
        pointer-events: all;
        position: relative;
        z-index: 10;
        -moz-appearance: none;
        width: 9px;
    }
    
    section.range-slider input::-moz-range-track {
        position: relative;
        z-index: -1;
        background-color: rgba(0, 0, 0, 1);
        border: 0;
    }
    section.range-slider input:last-of-type::-moz-range-track {
        -moz-appearance: none;
        background: none transparent;
        border: 0;
    }
      section.range-slider input[type=range]::-moz-focus-outer {
      border: 0;
    }
    <!-- This block can be reused as many times as needed -->
    <section class="range-slider">
      <span class="rangeValues"></span>
      <input value="5" min="0" max="15" step="0.5" type="range">
      <input value="10" min="0" max="15" step="0.5" type="range">
    </section>

    【讨论】:

    • 不幸的是,它不适用于 Android 4.0.4 Mobile Safari 4.0 浏览器。 :-(
    • @erik 我真的没有很好的方法来测试这些版本,但它适用于 Android 5.0 和最新版本的 Safari(谷歌播放说是 1.2,所以我对你的 4.0 感到困惑)。如果你弄明白了,我很想知道。
    • 真是太聪明了!我想知道它是如何没有被标记为正确答案的,因为它可以优雅地解决问题而没有任何依赖。添加 jQuery 只是为了做到这一点显然是矫枉过正。
    • @zanona 谢谢,但正确答案是在 4 年前标记的,所以我认为 OP 不太关心另一种解决方案。
    • 我真的很喜欢您的方法,并尝试将其调整到我的用例中,但当我意识到我拥有的一些设计规范(例如,为范围与轨道的其余部分不同)无法实现。所以我寻找了另一个解决方案,发现了这个非常简洁的项目:refreshless.com/nouislider 它没有依赖关系,有一个漂亮而干净的 API,兼容 AMD,并提供了很多选项。到目前为止,我对此非常满意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多