HTML5: Slider com duas entradas possíveis?

99

É possível fazer um controle deslizante HTML5 com dois valores de entrada, por exemplo, para selecionar uma faixa de preço? Se sim, como isso pode ser feito?

freqüente
fonte

Respostas:

64

Não, a entrada do intervalo HTML5 aceita apenas uma entrada. Eu recomendo que você use algo como o controle deslizante de intervalo da interface do usuário jQuery para essa tarefa.

Martin Buberl
fonte
Obrigado pelo link e informações. Tenho que verificar se consigo fazer isso funcionar em dispositivos móveis.
frequente
33
Algum tempo atrás ... mas eu consegui "falsificar" um controle deslizante duplo colocando dois controles deslizantes exatamente um em cima do outro. Um começando no valor mínimo, o outro começando no valor máximo. Eu acho que isso é trapaça, mas ... funciona para mim.
frequente
WhatWG está pelo menos discutindo sua implementação: html.spec.whatwg.org/multipage/…
kunambi
7
Eu gosto do ionRangeSlider um pouco melhor do que o controle deslizante da interface do jQuery: ionden.com/a/plugins/ion.rangeSlider/en.html
Charlotte
4
Outra abordagem é "falsificar" o controle deslizante duplo com controles de entrada lado a lado: simple.gy/blog/range-slider-two-handles
SimplGy
79

Eu estive procurando por um controle deslizante duplo leve e livre de dependências por algum tempo (parecia loucura importar jQuery apenas para isso) e não parece haver muitos por aí. Acabei modificando um pouco o código do @Wildhoney e gostei muito.

Gary
fonte
Infelizmente, ele não funciona com o navegador Android 4.0.4 Mobile Safari 4.0. :-(
erik
@erik Não tenho realmente uma boa maneira de testar essas versões, mas funciona para mim no Android 5.0 com a versão mais recente do Safari (que o Google Play diz ser 1.2, por isso estou confuso sobre o 4.0). Se você descobrir, eu adoraria saber.
Gary,
1
Isso é muito inteligente! Eu me pergunto como não está marcado como a resposta correta, já que resolve o problema de forma elegante, sem qualquer tipo de dependência. Adicionar jQuery apenas para fazer isso é obviamente um exagero.
zanona
@zanona Obrigado, mas a resposta correta foi marcada 4 anos antes, então não acho que o OP se importou muito com outra solução.
Gary
11
Eu realmente gosto da sua abordagem e tentei adaptá-la ao meu caso de uso, mas tive que desistir quando percebi que algumas das especificações de design que eu tenho (por exemplo, colorir a parte "ativa" da faixa de forma diferente do resto da trilha ) não são possíveis de implementar com isso. Então, procurei outra solução e achei este projeto realmente legal: refreshless.com/nouislider É livre de dependências, tem uma API limpa e agradável, é compatível com AMD e oferece muitas opções. Até agora estou muito feliz com isso.
Felix Wienberg
37

Chegando tarde, mas noUiSlider evita ter uma dependência jQuery-ui, o que a resposta aceita não. Sua única "ressalva" é que o suporte do IE é para o IE9 e mais recentes, se o IE legado for um obstáculo para você.

Também é gratuito, de código aberto e pode ser usado em projetos comerciais sem restrições.

Instalação: Baixe noUiSlider, extraia o arquivo CSS e JS em algum lugar do sistema de arquivos do seu site e, a seguir, vincule ao CSS do cabeçalho e ao JS do corpo:

<!-- In <head> -->
<link href="nouislider.min.css" rel="stylesheet">

<!-- In <body> -->
<script src="nouislider.min.js"></script>

Exemplo de uso: Cria um controle deslizante que vai de 0 a 100 e começa definido como 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
    }
});
dario_ramos
fonte
WOW, incrível !! Isso é exatamente o que precisávamos e está maravilhosamente desenvolvido! WHITOUT jQuery
DavidTaubmann
Deve ser bastante fácil adicionar isso você mesmo e enviar uma solicitação de pull para o projeto?
dario_ramos
3
Não investiguei, mas poderia usar o controle deslizante com o teclado, então acho que está implementado agora @ptrin :)
Edu Ruiz
21

Claro que você pode simplesmente usar dois controles deslizantes sobrepostos um ao outro e adicionar um pouco de javascript (na verdade, não mais do que 5 linhas) para que os seletores não excedam os valores mínimo / máximo (como em @Garys) da solução.

Em anexo, você encontrará um pequeno snippet adaptado de um projeto atual, incluindo alguns estilos CSS3 para mostrar o que você pode fazer (apenas webkit). Também adicionei alguns rótulos para exibir os valores selecionados.

Ele usa JQuery, mas uma versão vanillajs não é mágica.

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

user1532132
fonte
7
Ei, parece ótimo! mas não funciona no Firefox, você só pode arrastar a entrada máxima. Você conseguiu consertar isso?
Toni Michel Caubet
5
Oh cara. Vim aqui para adicionar quase exatamente a mesma coisa! simple.gy/blog/range-slider-two-handles Minha versão coloca as entradas lado a lado, mas também usa entradas duplas.
SimplGy
5

Na verdade eu usei meu script em html diretamente. Mas em javascript, quando você adiciona um ouvinte de evento de entrada para este evento, ele fornece os dados automaticamente. Você só precisa atribuir o valor de acordo com sua necessidade.

[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>

Himabindu
fonte