At a glance:
- The script can be used as an HTML5 input range polyfill solution
- Introduces a gradient filled “range bar” for quick visual feedback
- iOS Touch screen friendly
- Arrives with a new CSS3 skin that degrades gracefully in older browsers
- A small network footprint – only two HTTP requests and a total size (minified and gzipped) of about 11k
- Unobtrusive & namespace friendly
- Conforms to the WAI-ARIA defined role of “slider”
- Keyboard accessible
- Mousewheel compatible
- Responsive design friendly
The impatient amongst you may wish to view the basic demo or the yepnope (Modernizr.load) dependency loading demo before reading any further.
A word from the sponsor…
Before using the script, it is important to update the absolute filepaths within the CSS file to point to a loction on your server. Not doing this tends to send IE6 and IE7 into an absolute browser-locking frenzy when the script is used.
Simply run a find/replace within a text editor; replacing all occurrences of the string “the_absolute_path_to_this_file” with the absolute path to the file on your server (no trailing slash required). For example, if your file is positioned at
http://www.mysite.com/css/fd-slider.css
Then you would run a find/replace, replacing the_absolute_path_to_this_file by
http://www.mysite.com/css
Remember, don’t include the trailing slash on the directory path.
Using the script as an HTML5 range polyfill
The script can be used as an HTML5 input range polyfill i.e. it can replicate the functionality of the native HTML5 input range in browsers that do not support this new input type.
Ranges created by the script are given the input range API stepUp and stepDown methods in order to mimic the functionality of the native DOM interface. Additionally, all HTMLEvents (focus, blur & change) set on the original form element are honoured and form reset events taken into account.
There are two ways in which to add the script to your pages in order to use it as an HTML5 polyfill – old-school & new-school.
Old-School: Add all files to the HEAD of your HTML document
Add the required Javascript and CSS files to the head of the HTML document (as can be seen within the demo source code). If the browser supports input ranges, the script bows out gracefully and lets the browser take care of the heavy lifting.
This method does have the distinct disadvantage of always downloading the Javascript and CSS files, even when not required – which is nasty – so using the New-school method is preferable when using the script as a polyfill.
Polyfill creation is initiated when the window.onload event fires but, if you are already using an onDomReady solution, you can call the fdSlider.onDomReady(); method from within your own onDomReady code. This will remove the onload event and create the required ranges immediately.
New-School: Using yepnope (Modernizr.load) to load files
This solution means that the required files will only ever be downloaded when needed as Modernizr is used to test the browser for input range support.
If the browser does not support input ranges, only then will yepnope (a.k.a. Modernizr.load) download the required files from the server – which won’t penalise people using browsers that support the input range type with unnecessary downloads. It will also reduce the strain on your server, reduce your bandwidth costs and help make your site feel snappier – which can’t be bad.
Polyfill Caveats – aren’t there always.
- Setting the “step” attribute is mandatory as it’s the only way I can distinguish the range state from the number state (that, like the range state, uses both the “min” and “max” attributes)
- Unlike native range implementations, the
stepUpandstepDownAPI methods do not throw anINVALID_STATE_ERR. This is a good or bad thing depending on how you look at it - If a dataList has been associated with a range input, it is currently not taken into account by the script
HTML5 range polyfill & Vertical Ranges
The W3C spec for the input type=range stipulates that the orientation of the control should be determined from the ratio of the style-sheet-specified height and width properties. Basically, if you style the input height to be larger than the width, the browser should render a vertical range.
The script follows the specification and will test to see if the input height is larger than the width, creating a vertical range if this is the case. The range will inherit the pixel height set for the associated input element.
Using a custom data- attribute to create vertical sliders
Imagine the following scenario:
- You give a class to a range input that makes it 30px wide and 300px in height – this should instruct the browser to automatically create a vertical range
- Someone visits your site with a browser that does not support range inputs
- The non-supporting browser does its thing and falls back to displaying a basic text input in place of the requested range input
- Unfortunately, this “fallback” text input inherits the style declaration destined for the input range and is now rendered 30px wide and 300px in height. A usability nightmare.
Should a vertical range be required and you have sufficient control over the HTML, I suggest (for the moment) you add the custom data attribute data-fd-slider-vertical to the range input. This avoids the above scenario for visitors with Javascript disabled but has the downside of not creating a native vertical slider in browsers that support the input range type.
Additionally, the String value of this custom data attribute is given to the created polyfill as a className. This enables you to easily create a class that sizes your vertical ranges. An example of this is shown below:
<!-- Create a class to give to vertical ranges -->
<style>.vs { height:300px; }</style>
<!-- Use this class as the value of the "data-fd-slider-vertical" custom data attribute -->
<input name="html5RangeShim"
data-fd-slider-vertical="vs"
type="range"
min="0"
max="100"
step="1"
title="Range: 0 to 100 in steps of 1"
value="" />
Using the above HTML, the value of the data-fd-slider-vertical attribute (in this case “vs”) is given to the newly created range polyfill which forces a 300px vertical height. If Javascript has been disabled, no range polyfill will be created but users will not be left with a disproportionately styled fallback text input.
Using the Javascript A.P.I to create sliders
It is possible to use the Javascript API to create sliders – this gives access to a bit more functionality when compared to the HTML5 polyfill in that callback functions can be defined for various events and the sliders can be associated with either text inputs or select lists.
To create sliders using the Javascript API, just call the fdSlider.createSlider method, passing in an Object declaring the required parameters as name/value pairs; for example:
<input type="text" name="inputTest" id="inputTest" value="" maxlength="6" />
<script>
fdSlider.createSlider({
// Associate the slider with the form element
inp:document.getElementById("inputTest"),
// Use the "tween to click point" animation
animation:"tween",
// A minimum value of 5
min:5,
// A maximum value of 15
max:15,
// A step/increment of 0.2
step:.2
});
</script>
As can be seen in the above example, each slider has to be associated with an existing form element – either a text input or a select list – and a reference to this form element passed as the value of the inp parameter. The inp parameter is mandatory as without it, no slider is created.
Javascript API configuration parameters
When creating a slider using the Javascript API, the following parameters can be passed within the configuration Object:
| Parameter | Description |
|---|---|
inp |
A DOM reference to the sliders associated form element. This parameter is mandatory. |
min |
The sliders minimum value. An optional parameter that defaults to 0 if not set. |
max |
The sliders maximum value. An optional parameter that defaults to 100 if not set. |
step |
The sliders increment. An optional parameter that defaults to 1 if not set. |
maxStep |
The step to use when keyboard users press the CTRL key in conjunction with a directional arrow key. Defaults to two times the value of step if not set. |
animation |
The animation to use when animating the drag handle towards the click point. Valid values are “tween”, “jump” and “timed”. These are explained in more detail within the Handle Animations section. |
precision |
The number of decimal places displayed within the result. |
callbacks |
An Object of key value pairs where the keys represent the callback type and the value an Array of functions assigned to this callback. |
vertical |
An optional Boolean value that, when set to TRUE, instructs the script to create a vertical slider. Defaults to FALSE. |
hideInput |
An optional Boolean value that, when set to TRUE, instructs the script to hide the associated form element by giving it the class “fd-form-element-hidden”. Defaults to FALSE. |
classNames |
An optional String value that is given to the slider as a className. This enables you to set slider dimensions using CSS. |
forceValue |
An optional Boolean value that, when set to TRUE, instructs the script to always display a valid value within the associated text input. Defaults to FALSE. |
Working examples of the above parameters can be viewed within the demo source code.
Callback functions
The following callback events are currently supported for sliders created using the Javascript API:
| Callback | Description |
|---|---|
create |
Called whenever the slider is created and initially injected into the DOM. |
disable |
Called whenever the fdSlider.disableSlider method is called. |
enable |
Called whenever the fdSlider.enableSlider method is called. |
destroy |
Called whenever a slider is destroyed by calling the fdSlider.destroyAll or fdSlider.destroySlider methods. |
redraw |
Called whenever a slider is rerendered. |
focus |
Called whenever a slider gains focus. |
blur |
Called whenever a slider loses focus. |
update |
Called whenever the associated form element’s value gets updated (Note: This is different from the “change” callback as an “update” callback may not actually alter the form element value). |
change |
Called whenever the associated form element’s value changes. |
finalise |
Called whenever the drag handle animation completes. |
move |
Called whenever the drag handle moves position during an animation. |
Each callback function gets passed the following Object as an argument:
{
"disabled":[Boolean value set to TRUE when the associated form element is disabled],
"userSet":[Boolean value that indicates if the user has manually selected a value],
"elem":[A reference to the associated form element],
"value":[The associated form elements current value]
}
The Javascript API
The script creates one Javascript Object fdSlider within the global namespace. This Object has the following Public methods:
| Method | Description |
|---|---|
createSlider(opts) |
Creates a slider using the options passed within the “opts” argument. |
destroyAll() |
Destroys all sliders i.e removes them from the DOM |
destroySlider(id) |
Destroys the slider associated with the form element whose ID attribute matches the value of the single argument |
redrawAll() |
Rerenders all of the current sliders |
increment(id, numSteps) |
Increments the slider associated with the form element whose ID attribute matches the value of the “id” argument by the number of steps given within the “numSteps” argument. Negative values are permitted. |
stepUp(id) |
Increments the slider associated with the form element whose ID attribute matches the value of the “id” argument by one step. |
stepDown(id) |
Decrements the slider associated with the form element whose ID attribute matches the value of the “id” argument by one step. |
setRange(id, newMin, newMax) |
Sets a new selectable range for the slider associated with the form element whose ID attribute matches the value of the “id” argument. The range does not set new max and min values, just a selectable range between the original values. |
updateSlider(id) |
Updates the slider associated with the form element whose ID attribute matches the value of the “id” argument. Helpful when you use JS to change the associated form elements value. |
onDomReady(id) |
HTML5 Polyfill use only. Removes the window.onload event that creates the input range polyfills and creates the sliders immediately. |
The HTML
The following HTML is created by the script for every slider and inserted into the DOM before the associated form element:
<span
class="fd-slider"
id="fd-slider-[associated form element ID]"
role="application">
<span class="fd-slider-inner"></span>
<span class="fd-slider-range"></span>
<span class="fd-slider-bar"></span>
<span
tabindex="0"
class="fd-slider-handle"
role="slider"
aria-disabled="false"
aria-valuemin="[the minimum possible value]"
aria-valuemax="[the maximum possible value]"
aria-labelledby="[associated form elements label]"
id="fd-slider-handle-[associated form element ID]"
aria-describedby="fd-slider-describedby"
aria-valuenow="[the current value]"
aria-valuetext="[the current value]"> </span>
</span>
The default CSS skin
The script now gives the BODY a class of “oldie” when using Internet Explorer (any version lower than 9). This enables me to use a combination of the .oldie className and safe CSS hacks to target Internet Explorer within the CSS file, meaning that only one CSS file is now required by the script.
All images have been been BASE 64 encoded within the CSS file (and MHTML used to BASE 64 encode the files for Internet Explorer 6 and 7).
The skin (and script) should play nicely with responsive sites and redraw the sliders/polyfills whenever the window.resize event fires. Resizing the browser window within the demo will show how the slider adapts to changes in its parent containers width.
The CSS file is heavily commented and so altering styles, like the colour of the gradient used on the range bar for example, shouldn’t be a problem (but a certain knowledge of CSS is still required).
The skin liberally uses CSS gradients, border radius, rgba colours & box shadows. To try to keep Internet Explorer in line, I’ve borrowed much from the Microsoft book of Dark Arts. Depending on what version of Internet Explorer the script is running under, some or all of the following proprietary behaviours & filters are used: Blur, Gradient & Alpha Image loader filters, MHTML Base64 encoded images and CSS expressions.
Those of you not wanting to dive into the absolute nerdery of a detailed technical overview of the CSS might want to skip straight to Setting Global configuration Parameters
Internet Explorer Styling Woes
As mentioned previously, the default skin uses quite a few proprietary Internet Explorer filters and behaviours. For the most part, this is an attempt to present the most unified visual experience as possible across browsers. Occasionally, this is to fix a bug in the Trident rendering engine. Here’s a quick rundown of the various proprietary technologies used and why.
The AlphaImageLoader filter
As Internet Explorer 6 cannot correctly render transparent png images, the AlphaImageLoader filter was used in order to display the png slider drag handle. As the filter does not enable background positioning, it is impossible to use an “image sprite” when styling the various drag handle animation states (mouseover state, disabled state etc). This meant that the large sprite containing all of the combined drag handle states, had to be split into separate, individual png images.
While the AlphaImageLoader filter solved the problem of using png images for the drag handle, It also made the rollover effect for the drag handle animation “flicker”, as the browser attempted to download the image representing the new animation state from the server.
This new “flicker” problem was solved by base 64 encoding the individual png images and using MHTML to include them in the relevant CSS file as plain text. This is explained in more detail below…
Why I stopped worrying and learned to love MHTML
Internet Explorer ships with a proprietary technology called MHTML. One of MHTML’s quirks enables you to base64 encode images as plain-text and include this text within a specially formatted comment block at the top of the CSS file. References to this image within the CSS file then point to the base64 encoded plaintext version of the image embedded within the comment block.
This means that the image downloads as part of the CSS file itself which also means that it is available for use immediately – the browser never needs to make the traditional and additional http request normally reserved for downloading the image from the server.
One immediate benefit to base 64 encoding the images like this was that the problematic “flicker” on the drag handle animation within IE6 was instantly resolved. As all images are effectively downloaded with the CSS file, swapping images when changing drag handle states is instantaneous.
Base64 encoded images were used to fix another more serious usability issue within Internet Explorer (6 and 7), the “disappearing clickable area” bug.
Internet Explorer does not seem to fire mouse events for dynamically created elements that do not have a solid background colour or a background image set. As the default CSS skin sets a transparent background colour on the the sliders wrapper element, this effectively disables mouse events in Internet Explorer unless the cursor is positioned directly over the inner track bar (which has a solid border and background colour and so reacts to mouse events). This hinders usability as the sliders original clickable area has now shrunk to be the 4px width/height of the inner track bar.
To make mouse events work within Internet Explorer over the entire slider, a 200px x 200px transparent gif image has been base64 encoded within the CSS file. The background to the slider has then been set to point to this base64 encoded transparent image. As the slider has been given a background image, mouse events mysteriously work again and the full clickable area returns.
The Gradient filter
The proprietary Gradient filter was used to replicate the CSS gradients for Internet Explorer 6, 7 and 8.
The Blur filter
In Internet Explorer 6, 7 and 8, the glow effect given to the slider whenever it gains focus is achieved by using of the proprietary Blur filter. All other browsers use the box-shadow CSS property (or a vendor prefixed derivative).
Unfortunately, the Blur filter destroys absolute positioning (as the Blur radius appears to become part of the elements box model) and so it has been applied to the span with a class of “fd-slider-inner” and not, as is the case with all other browsers using box-shadow, the span with a class of “fd-slider-bar” i.e. the track bar itself.
CSS expressions
CSS expressions are used to hide the focus outline in Internet Explorer versions 6, 7 and 8. Internet Explorer 6, as it cannot absolutely position an element on four sides, also uses an expression to dynamically calculate a suitable dimension for the slider track bar.
Setting Global configuration parameters
The script accepts the passing of Global configuration parameters by using a JSON Object within the script tag – an example of this is shown below:
<!-- The JSON Object is passed within the script tag -->
<script src="/the/path/to/fd-slider.js">
{
"html5Animation":"tween",
"describedby":"slider-instructions"
}
</script>
It’s worth noting that JSON notation doesn’t care about whitespace so the above code block could have been written in one line (with no line breaks). Additionally, you can programmatically pass the JSON Object by calling the fdSlider.setGlobalVariables method as is shown below:
<!-- Load the script -->
<script src="/the/path/to/the/script.js"></script>
<!-- Now create our JSON Object and pass it to the "setGlobalVariabless" method -->
<script>
// Pass the JSON to the script immediately...
fdSlider.setGlobalVariables({
// Set the animation used for HTML5 polyfill sliders
"html5Animation : "tween"
});
</script>
The following global configuration parameters can be passed to the script using JSON:
| Parameter | Description |
|---|---|
mousewheelEnabled |
Accepts a boolean value that enables/disables mousewheel events for all sliders. Defaults to TRUE. |
fullaria |
Accepts a Boolean value that instructs the script to either use a SPAN (TRUE) or an A (FALSE) element for the drag handle. Defaults to TRUE. |
describedBy |
Accepts a String that represents the ID attribute of the DOM node you wish to set as the ARIA DescribedBy hook. |
noRangeBar |
Accepts a boolean value that enables/disables the creation of the range bar for all sliders. Defaults to FALSE. |
html5Animation |
Accepts a String that defines the type of “animation to click point” to use for HTML5 polyfills. Valid values are “tween”, “jump” and “timed”. Defaults to “jump”. |
Handle Animations
The script enables three types of animation to be used when moving the drag handle towards the click/tap point. HTML5 range polyfills have a default animation of “jump” while sliders created using the Javascript API have a default animation of “tween”.
“jump”
The jump animation immediately moves the drag handle to the click point
“timed”
The drag handle is progressively moved towards the click point one step at a time using a 50 millisecond timer
“tween”
A tween animation is used to move the drag handle towards the click point.
ARIA roles & States
The script gives the outermost SPAN the role “application”, the slider drag handle the role “slider” and assigns the ARIA properties aria-valuenow, aria-value-min, aria-value-max, aria-value-text and, if possible, aria-describedby.
If using the Javascript API and associating a slider with a selectlist, the aria-valuetext property is set not to the current option.value but to the options text content.
For example, when using the following HTML:
<select name="myselect" id="myselect">
<option value="1">Cherry</option>
<option value="2">Hickory</option>
... snip ...
</select>
The aria-valuetext value will be set to “Cherry” when the first option is selected and “Hickory” when the second option is selected, not the Integer values 1 and 2.
Demo & Downloads
The latest & greatest version of the script can be found on gitHub: https://github.com/freqdec/fd-slider.
The following demos are currently available: the basic (old-school) demo, the yepnope/Modernizr (new-school) hybrid demo and an experimental tooltip demo showing how to use CSS generated content to create a “tooltip” that displays the sliders current value. The tooltip demo is not suitable for consumption in Internet Explorer – but that shouldn’t come as any surprise at this stage of the game.
Please note: I’ve not minified the code at all which is something you should do before using it in a production environment. Minified and gzipped brings the network footprint down to around 11k for both the Javascript and CSS file.
Related Links
If you have read this far then well done! Here’s a few links that may interest you further.
- An explanation on using the MHTML syntax by Stoyan Stefanov
- The yepnope website
- The Modernizr website
- The W3C spec for the input type=range – imprecise number-input control
- The WAI-ARIA working draft
- Safe CSS Hacks by Mathias Bynens
- Info on how to style generated content & the associated pitfalls by Nicholas Gallagher

Comments are currently closed but feel free to contact me on twitter with your questions or suggestions - I’d love to hear from you.