7

So I have recently been playing around with styling the html range slider.

I came across a pen on CodePen that has some really great designs.

This is the source code from one.

HTML:

<input type="range" data-idx="1">

CSS:

html {
  background: #393939;
}

input[type='range'] {
  display: block;
  margin: 2.5em auto;
  border: solid .5em transparent;
  padding: 0;
  width: 15.5em;
  height: 1em;
  border-radius: .25em;
  background: transparent;
  font-size: 1em;
  cursor: pointer;
}
input[type='range'], input[type='range']::-webkit-slider-runnable-track, input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
}
input[type='range']::-webkit-slider-runnable-track {
  width: 15.5em;
  height: 0.5em;
  border-radius: 0.25em;
  background: #fff;
}
.js input[type='range']::-webkit-slider-runnable-track {
  background: linear-gradient(#e44e4f, #e44e4f) no-repeat #fff;
}
input[type='range']::-moz-range-track {
  width: 15.5em;
  height: 0.5em;
  border-radius: 0.25em;
  background: #fff;
}
.js input[type='range']::-moz-range-track {
  background: linear-gradient(#e44e4f, #e44e4f) no-repeat #fff;
}
input[type='range']::-ms-track {
  border: none;
  width: 15.5em;
  height: 0.5em;
  border-radius: 0.25em;
  background: #fff;
  color: transparent;
}
input[type='range']::-ms-fill-lower {
  border-radius: 0.25em;
  background: #e44e4f;
}
input[type='range']:nth-of-type(1)::-webkit-slider-runnable-track {
  background-size: 50% 100%;
}
input[type='range']:nth-of-type(1)::-moz-range-track {
  background-size: 50% 100%;
}
input[type='range']:nth-of-type(1)::-webkit-slider-thumb {
  margin-top: -0.125em;
  border: none;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  box-shadow: 0 0 0.125em #333;
  background: #fff;
}
input[type='range']:nth-of-type(1)::-moz-range-thumb {
  border: none;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  box-shadow: 0 0 0.125em #333;
  background: #fff;
}
input[type='range']:nth-of-type(1)::-ms-thumb {
  border: none;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  box-shadow: 0 0 0.125em #333;
  background: #fff;
}
input[type='range']:nth-of-type(1)::-ms-tooltip {
  display: none;
}
input[type='range']:focus {
  outline: none;
  box-shadow: 0 0 0.25em #e44e4f;
}

Javascript:

var s = document.createElement('style'), 
    r = document.querySelectorAll('input[type=range]'), 
    prefs = ['webkit-slider-runnable', 'moz-range'], 
    styles = [], 
    l = prefs.length
    n = r.length;

document.body.appendChild(s);

var getTrackStyleStr = function(el) {
  var str = '', 
      j = el.dataset.idx, 
      min = el.min || 0, 
      perc = (el.max) ? ~~(100*(el.value - min)/(el.max - min)) : el.value, 
      val = perc + '% 100%';

  for(var i = 0; i < l; i++) {
    str += '.js input[type=range]:nth-of-type(' + j + ')::-' + prefs[i] + '-track{background-size:' + val + '}';
  }

  return str;
};

var getTipStyleStr = function(el) {
  var str = '.js input[type=range]:nth-of-type(' + el.dataset.idx + ') /deep/ #thumb:after{content:"' + el.value + '%"}';

  return str;
};

for(var i = 0; i < n; i++) {
  styles.push('');

  r[i].addEventListener('input', function() {    
    styles[this.dataset.idx] = getTrackStyleStr(this);
    if(this.classList.contains('tip')) {
      styles[this.dataset.idx] += getTipStyleStr(this);
    }

    s.textContent = styles.join('');
  }, false);
}

This works great for one range element but if I try adding more range elements on the same page, and change the data attribute to data-idx="2" it will not work, the first range will control them all.

How can I adjust the code to make each range work independently?

Here is a JSFiddle of the code I'm using, for some reason the javascript isn't working on there at all, but it's works fine on codepen? Hmm...

Here is the original Codepen

3
  • It does not work on codepen with multiple idx elements either Commented Jun 1, 2015 at 18:28
  • Yeah I know, that's why I needing to adjust the javascript. Commented Jun 1, 2015 at 18:38
  • Ok I fixed it! not a big deal ... just some strange code from babydino with those idx and /deep/ stuff rsrss Commented Jun 1, 2015 at 19:03

2 Answers 2

1

SOLUTION

var r = document.querySelectorAll('input[type=range]'), 
    prefs = ['webkit-slider-runnable', 'moz-range'], 
    styles = [], 
    l = prefs.length,
    n = r.length;

var getTrackStyleStr = function(el, j) {
  var str = '', 
      min = el.min || 0, 
      perc = (el.max) ? ~~(100*(el.value - min)/(el.max - min)) : el.value, 
      val = perc + '% 100%';

  el.previousElementSibling.textContent = el.value;
  
  for(var i = 0; i < l; i++) {
    str += "input[type=range][data-rangeId='" + j + "']::-" + prefs[i] + '-track{background-size:' + val + '} ';
  }
  return str;
};

var setDragStyleStr = function(evt) {
  var trackStyle = getTrackStyleStr(evt.target, this); 
  styles[this].textContent = trackStyle;
};

for(var i = 0; i < n; i++) {
  var s = document.createElement('style');
  document.body.appendChild(s);
  styles.push(s);
  r[i].setAttribute('data-rangeId', i);
  r[i].addEventListener('input', setDragStyleStr.bind(i));
}
html {
  background: #393939;
}

div {
  margin: 2.5em auto;
}

input[type='range'] {
  display: block;
  margin: 0.2em auto;
  border: solid .5em transparent;
  padding: 0;
  width: 15.5em;
  height: 1em;
  border-radius: .25em;
  background: transparent;
  font-size: 1em;
  cursor: pointer;
}
input[type='range'], 
input[type='range']::-webkit-slider-runnable-track, 
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
}
input[type='range']::-webkit-slider-runnable-track {
  width: 15.5em;
  height: 0.5em;
  border-radius: 0.25em;
  background: #fff;
}
input[type='range']::-webkit-slider-runnable-track {
  background: linear-gradient(#e44e4f, #e44e4f) no-repeat #fff;
}
input[type='range']::-moz-range-track {
  width: 15.5em;
  height: 0.5em;
  border-radius: 0.25em;
  background: #fff;
}
input[type='range']::-moz-range-track {
  background: linear-gradient(#e44e4f, #e44e4f) no-repeat #fff;
}
input[type='range']::-ms-track {
  border: none;
  width: 15.5em;
  height: 0.5em;
  border-radius: 0.25em;
  background: #fff;
  color: transparent;
}
input[type='range']::-ms-fill-lower {
  border-radius: 0.25em;
  background: #e44e4f;
}
input[type='range']::-webkit-slider-runnable-track {
  background-size: 0% 100%;
}
input[type='range']::-moz-range-track {
  background-size: 0% 100%;
}
input[type='range']::-webkit-slider-thumb {
  margin-top: -0.125em;
  border: none;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  box-shadow: 0 0 0.125em #333;
  background: #fff;
}
input[type='range']::-moz-range-thumb {
  border: none;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  box-shadow: 0 0 0.125em #333;
  background: #fff;
}
input[type='range']::-ms-thumb {
  border: none;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  box-shadow: 0 0 0.125em #333;
  background: #fff;
}
input[type='range']::-ms-tooltip {
  display: none;
}
input[type='range']:focus {
  outline: none;
  box-shadow: 0 0 0.25em #e44e4f;
}

output[for='range'] {
  font-family: "Lucida Grande","Lucida Sans Unicode", Tahoma, Sans-Serif;
  font-size: 13px;
  color: white;
  display: block;
  text-align: center;
}
<div>
  <output for="range">0</output>
  <input type="range" value="0">
</div>
<div>
  <output for="range">0</output>
  <input type="range" value="0">
</div>
<div>
  <output for="range">0</output>
  <input type="range" value="0">
</div>

Sign up to request clarification or add additional context in comments.

16 Comments

Wow, this is working perfectly. Yeah babydino has quite a few examples of sliders and she uses the same javascript for most of them, it was confusing me how she had wrote some of it and using the data-idx. Great job on simplifying it though, thanks! :)
Also, do you have any idea why the code wasn't working when I copied it into a jsfiddle?
Just been testing your code and noticed if you put one of the inputs into a div tag for example, the code breaks. Could you possibly update your answer with a fix for this?
I was meaning if you wanted to put each input into a separate div, like this - jsfiddle.net/wrahef1p/4
I'm still learning javascript so sorry if this is a silly question but couldn't you use something like (this) so it would only effect the slider that you're controlling instead of giving each slider an id?
|
0

Jquery UI offers some functional sliders that can be used in multiple instances on a page. You don't have to write or modify as much code to use them as above. Unless you are trying to avoid jquery, this may be a better option for you.

Here is a link to the multiple sliders demo.

The approach used for multiple sliders relies of course on jquery, but given markup such as:

<div id="eq">
    <span>88</span>
    <span>77</span>
    <span>55</span>
    <span>33</span>
    <span>40</span>
    <span>45</span>
    <span>70</span>
</div>

A simple .each statement handles setting them all up.

$( "#eq > span" ).each(function() {
  // read initial values from markup and remove that
  var value = parseInt( $( this ).text(), 10 );
  $( this ).empty().slider({
    value: value,
    range: "min",
    animate: true,
    orientation: "vertical"
  });
});

Edit: As per comments below, if you want to add tool-tips / hints, you have to roll your own. Here's a brief example from some code I wrote last year. It has some specific behaviors that fit the needs of my users, but this should give you an idea. The id "hintrow" refers to a table row on a grid that contained my slider. Through experimentation, you can probably find the best place relative to your various sliders to append this. It will get positioned so you only want a dom node to append it to.

function drawExtCues(){
    z = 200;
    $('#hintrow').append('<div id="hintContainer" style="position:relative"></div>');
    for(h in rowobjects){
        z++;
        $('#hintContainer').append('<div title="' + rowobject[h].property1 + '" class="' + rowobject[h].property2+ ' ui-slider-range hint" style="z-index:' + z +';">' + rowobject[h].property1+ '</div>');
    }
    $('.hint').mouseover(function(){
            hintMouseOver();                
        });     
  }

  function hintMouseOver(){
    $('.hint').addClass('hintInspect',500);
    $('.hint').unbind('mouseover');
    $('.hint').click(function(){
            $J('.hint').removeClass('hintInspect',500);
            $J('.hint').mouseover(function(){hintMouseOver();})
        });                 

  }

Note the z++. This was used to ensure my tool-tips would stack. Since we made them click to dismiss in our case, this worked well. You don't have to do this, but if you don't use a click to dismiss, you might want to bind a timeout to clear the tool tip for you.

The hintMouseOver function does some house cleaning, like unbinding itself to prevent repeat calls. It is rebound after the click event to dismiss the tool tip is fired. This is just the behavior my client wanted. You could do a lot of things here. The class hintInspect is basically the style rules for how your tool-tip will appear. You can make it look any way you like. I think I just used a simple black outline with grey background.

6 Comments

How easy would it be to style the slider? I'm wanting to use similar styles to what I posted above. I'm also needing to get an output from the slider, I'm wanting to expand onto this and have a bubble above the slider that displays the value.
You can use the jquery ui theme roller or you can just write your own stylesheet. The inserted slider control has predictable class names that you can inspect to write your own style rules, which I've done on my own, and hence suggest you use the jquery themes as they look nice out of the box with little work. I think there's even a silver on black one like your fiddle.
Check out jqueryui.com/themeroller the theme gallery. I had to roll my own tool tip (bubble with value) when I used this. It wasn't terribly difficult but did take some experimentation. The API documentation shows you how to read the values or bind events to the change / click / drag so you can perform a number of bindings.
Since you have already overcome this problem, do you think you could possibly mock me up a demo on jsfiddle with code you used? Would really appreciate that. :)
Tool tip example added.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.