I'm Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with HTML, CSS and SVG. To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

my books

Pro CSS3 Animation book coverPro CSS3 Animation, Apress, 2013

my other blogs

Massive Head CanonMassive Head Canon: Intelligent discussion of movies, books, games, and technology.

my projects

The New DefaultsThe New Defaults — A Sass color keyword system for designers.

CSSslidyCSSslidy — an auto-generated #RWD image slider. 3.8K of JS, no JQuery.

Playing With The HTML5 range Slider Input

Using, transforming and adapting sliders across browsers

Playing With The HTML5 range Slider Input

Among the many new form elements that HTML5 has introduced, range is perhaps the oddest but also the most generally useful. Previously requiring a great deal of JavaScript coding or a framework to generate, you can now create a slide control natively in all modern browsers with a single element.

range is particularly useful for forms in which three conditions exist:

Think of a shipping form that judges the price of posting a package based on weight. The lowest weight might be an envelope with a sheet of paper (about 10 grams), with an upper limit of 2 kilos. Let’s say the price of shipping changes with every 100 grams added or removed. It’s very likely that the user will want to find the most economic deal, and could be expected to play within the weight limits for their package. In that case, appropriate markup could be:

<label for=weight>Weight</label>
<input type=range id=weight min=10 value=10 max=2000 step=100>

The alternatives – a drop-down select option or a number input - would be irritating to use, but a range slider is perfect.

In contrast, take a restaurant booking form, where the number of guests has an obvious upper and lower limit, but a user would be expected to approach the form with a set number already in mind. In that case, “playing” with a slider to find the right number of seats to book for the evening would be frustrating, making a number input would be far more appropriate.

Setup, Accessibility And Attributes

At the basic level, a range input should have at least three attributes: min (the lowest accepted value), max (the highest) and value (the default, or starting value). Form inputs should have associated label elements, meaning that the range should also have an id attribute in most cases. Let’s use the example of a volume control:

<label for=fader>Volume</label>
<input type=range min=0 max=5 value=3 id=fader>

Which produces:

Note that the slider UI has a few unique features:

  • When focused, the button can be moved with up/down cursor keys, just like the number input. (Not all browsers support this behavior yet).
  • The extent of the slider does not change according to the value of max; instead, it is adjusted by changing the width of the element in CSS. The relative position of the snap points will be adjusted in response to this change.

The “snapping” behavior of the range button can be particularly confusing when min and max are relatively close. As an example, let’s set of the range of the volume fader between 0 and 1:

<input type=range min=0 max=1 value=1 id=fader>

The button now snaps to the terminus of the range, with no intermediate positions. The solution is to introduce more granularity by using a step attribute value:

<input type=range min=0 max=1 value=1 id=fader step=".05">

Note that just like the number input, step can be used to allow only certain integers in a range: you can accept only even numbers between min and max by setting step=2, for example. Also note that the use of HTML5 shortcuts is limited in this case: you must use quotes around values like 0.5 in order for the code to be valid. A value of all for step makes the slider register floating-point values, and is the finest level of control.

Show and Tell

The range input doesn’t present a numerical readout of its value by default. To remedy that, we use the <output> element, together with a little JavaScript:

<label for=fader>Volume</label>
<input type=range min=0 max=100 value=50 id=fader step=1 onchange="outputUpdate(value)">
<output for=fader id=volume>50</output>
<script>
function outputUpdate(vol) {
  document.querySelector('#volume').value = vol;
}
</script>

Which (with the caveat noted below) produces:

One unusual behavior: Chrome, Safari and IE repond to onchange with an immediate alteration of the associated output value, while Firefox does not present a value change until the mouse is released. The Mozilla development team’s reasons for doing to can be read in the associated bug tracker report; while I don’t disagree with their philosophy, I think the UI approach taken by other browsers has better use-case support, and I am hopeful that Firefox will eventually bend to the majority approach. For right now, changing the event from onchange to oninput, which I did in the working example above, will create the same UI behavior across all supporting browsers.

Another issue to be aware of: the slider does not yet respond well to significant page scaling in Webkit. Doing so scales the slider bar out of alignment. To fix this, you can style the slider elements (the range bar and thumb) independently, using the CSS shown below.

Going Vertical

Orienting a slider vertically on a web page will occasionally make sense: most users think of volume as “up” and “down”, for example, rather than side-to-side. A reasonable expectation is that using CSS transforms would rotate the element correctly, but that won’t work as expected. Right now, the three major browsers each have a distinct way of making a range input vertical:

In Firefox, it’s an attribute: orient="vertical"

In Webkit, it’s CSS: -webkit-appearance: slider-vertical

And Microsoft have chosen a rather, um, rather distinct solution: writing-mode: bt-lr;

In this case it’s my hope that the Mozilla approach becomes the standard, but right now orient=vertical will be flagged during validation. As always, expect things to change in the future.

Combining all three would produce the following:

input.vertical { -webkit-appearance: slider-vertical;  writing-mode: bt-lr; }
<input type=range min=0 max=100 value=50 class=vertical orient=vertical>

… and the result you see to the right.

Styling The Slider

The appearance of the range slider can be customized completely in CSS, using a variety of pseudo-selectors:

input[type=range], ::-moz-range-track, ::-ms-track {
-webkit-appearance: none;
background-color: 3f91e5;
width: 250px;
height:20px;
}

At this point, the slider button can be customized:

::-webkit-slider-thumb, ::-moz-range-thumb, ::-ms-thumb {{
-webkit-appearance: none;
background-color: #666;
width: 10px;
height: 20px;
}

With the right selectors, the appearance of the slider can be made equivalent across browsers, as the default – dipping as it does into the UI of the operating system to determine the style of the element – can look very different from one browser to the next.

Generating Tick Marks On The Range Slider

The HTML5 spec allows for a particularly clever feature: linking the element to a datalist with numeric values via the list attribute will create a series of ticks along the length of the range bar, with the position of each tick determined by an option in the datalist. For example, a variation of our audio control:

<label for=fader>Volume</label>
<input type=range min=0 max=100 value=50 id=fader step=20 list=volsettings>
<datalist id=volsettings>
<option>0</option>
<option>20</option>
<option>40</option>
<option>60</option>
<option>80</option>
<option>100</option>
</datalist>

Combined with the CSS above, creates the following:

In IE, these ticks can be customized by manipulating the appearance of the pseudo-elements ::-ms-ticks-before and ::-ms-ticks-after (the areas above and below the slider thumb, respectively).  Unfortunately no other browser yet supports this degree of control, and Firefox does not present any ticks at all, at least as of FF 29.

Multiple Slider Buttons

In theory the range input should be able to take multiple comma-seperated values, generating multiple slider buttons:

<input type="range" value="7,9" min="0"  max="10" name="range" multiple>

This would be very useful for indicating upper and and lower range limits, but sadly no browser (as of this writing) supports this specification feature.

Out of The Form

One of the benefits of HTML5 is that input elements no longer have to be associated with form tags, allowing you to place the elements anywhere on a page, not just in forms. This will make the range slider increasingly useful for all kinds of UI controls.

Browser Compatibility & Polyfill Solutions

The range input is supported in all modern browsers: all versions of Chrome, Safari and Opera; iOS 5+, IE 10+, Firefox 23 and higher.

Making it work in older browsers is usually a matter of applying the right polyfill: html5slider by Frank Yan works very well for Firefox, rangeslider and the JQuery Tools rangeinput work very well across all browsers as a polyfill if you're using JQuery, with many more options are available.

Photograph by Peter Ma, used with permission.

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.