We all as a developers know the importance of the <input />
tag element, without it, we wouldn't have a way to receive any input from the user.
There are a lot of types that we can use on an input
element, and each one, change the behavior of the element, here's a list of the most common types of input's:
- text: The default value. A single-line text field.
-
button: A push button with no default behavior displaying the value of the value attribute, empty by default. If it's inside a
<form>
tag, it will submit the form when pressed.
- checkbox: A check box allowing single values to be selected/deselected.
- color: A control for specifying a color; opening a color picker when active in supporting browsers.
- email: A field for editing an email address. Looks like a text input, but with validation parameters on supported devices.
- password: A single-line text field whose value is obscured. Will alert user if site is not secure.
- number: A control for entering a number. Displays a spinner and adds default validation when supported.
- hidden: A control that is not displayed but whose value is submitted to the server.
- range: A control for entering a number whose exact value is not important. Displays as a range widget defaulting to the middle value.
As we can see, there are a lot of types that we can use, you can check them in deep here
<input type="range" />
In this post I'm going to show you how to modify the default style for the range input type so it looks better.
NOTE: All the code below works only on Chrome and Opera, TBH I didn't even try to fix any visual bug on any other browser.
The very basic implementation of an input range looks like this:
<input type="range" />
This will render the same as the saw above:
We have available some extra properties when using this element:
-
value
: String representation of a number, although it can't be an empty string (""
). The default value is always halfway betweenmin
andmax
properties. This is how is calculated:
defaultValue = (rangeElem.max < rangeElem.min) ? rangeElem.min
: rangeElem.min + (rangeElem.max - rangeElem.min)/2;
max
&min
: The maximum and minimum value permitted.step
: The stepping interval.list
: The id of the<datalist>
element that contains optional pre-defined options.
Ok! enough with HTML Input 101, let's put a style on that input!.
First we need the basic html structure, something like this:
<div class="container">
<datalist id="custom-list">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
<option value="6"></option>
<option value="7"></option>
<option value="8"></option>
<option value="9"></option>
<option value="10"></option>
<option value="11"></option>
</datalist>
<input type="range" min="1" max="10" step="1" list="custom-list"/>
</div>
The markup above will render this:
It renders a hash mark for each <option>
of the <datalist>
element.
Thumb and tracker
On any slider control, we have 2 element that we can interact to, the thumb and the tracker, the thumb is just the little widget that let you drag and drop along the track:
They're called Shadow DOM elements and we can actually style them with CSS, so let's start by that.
Enable user agent shadow DOM
I recommend you to enable the Shadow DOM on your browser, since we can't inspect this elements by default, and sometimes it's easier to just manipulate the element directly from the developer tools instead of the common process: change, save & reload.
I'll show you how to activate it using Opera, but this works the same on Chrome, and I'm pretty sure that on FF it's just as easy as it is on Opera (is just a checkbox, shouldn't be a big issue on any browser).
So, first open the Developer Tools (F12) in your browser, once its open, either press F1 or use the kebab menu (A.K.A 3 dots menu) and click on the "settings" option:
This will open the settings section. Next, we only need to check the option "Show user agent shadow DOM" under the Elements list:
Now, if we inspect the input, instead of looking like a regular input element:
We'll see the markup a bit different:
The input has elements inside, which represent the tracker and the thumb, now will be easier to inspect and modify the styles for this elements.
Styling
Let's start by styling our container element and removing the default look & feel of the input
.container {
position: relative;
max-width: 450px;
overflow: hidden;
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
}
To style the thumb and the tracker we have the pseudo-elements:
-
::-webkit-slider-runnable-track
: Selector for the tracker. -
::-webkit-slider-thumb
: Selector for the thumb.
IE and FF also have their pseudo-elements:
:-moz-range-track
and::-moz-range-thumb
for FF,::-ms-track
and::-ms-thumb
for IE
Using this, we'll apply our custom styles, let's start with the tracker:
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 1.2em;
cursor: pointer;
border: 1px solid #29334f;
overflow: hidden;
}
We set a border around the tracker and hide all the overflow content, now should look something like this:
I know, I know! It looks really ugly, so lets fix that by applying some style to the thumb:
input[type="range"]::-webkit-slider-thumb {
height: 12px;
width: 45px;
cursor: pointer;
-webkit-appearance: none;
border-bottom: 1px solid #29334f;
box-shadow: 0 0 0 red, -40px 0 0 red, -85px 0 0 red, -130px 0 0 red,
-175px 0 0 red, -220px 0 0 red, -265px 0 0 red, -310px 0 0 red,
-350px 0 0 red, -390px 0 0 red, -409px 0 0 red;
background: black;
}
First remove the default look & feel for the thumb, then we create a box shadow (10 actually) for the thumb and position them one behind the other, so now the input looks better:
Remember, we have the shadowDOM active, if something doesn't look the same, just inspect the element and change the style as you need.
Now, all we need to do is put some style in the <datalist>
element:
#custom-list {
display: flex;
justify-content: space-between;
}
#custom-list option {
position: relative;
background: white;
top: 18px;
border-left: 1px solid black;
border-right: 1px solid black;
}
Our datalist have a display flex and its items are align with a space between them, next, we just position all the datalist element upfront our input range (it was at the top). Finally we just set left and right borders on each option element. This is how it looks like:
Even though our input range is start taking shape, still looks a little weird, so let's fix it.
The first problem, is the first option
element with 2 borders, we don't need that, so let's hide it
#custom-list option:first-of-type {
visibility: hidden;
}
But that's not enough, we also need to fix the height of option
so the top border of the option
element will overflow a little bit the top border of the tracker.
You can base on the height we define for the thumb, in this case:
12px
#custom-list option {
...
min-height: 12.5px; # just a little bit more
}
If we look at the end of our input range, we still se a weird border, something like "]" (is actually our input track), to fix that, let's set overflow: hidden
to the .container
element:
.container {
...
overflow: hidden;
}
And last but not least, let's remove the ugly focus
effect that the input have by default:
input[type="range"]:focus {
outline: none;
}
And there you go!! Now you have a great looking input range, using only a few lines of CSS.
You can check the full code here.
Happy coding!! 💻🤓
Top comments (1)
Checkout my input-range implementation:
codepen.io/vsync/pen/mdEJMLv?edito...