Otro caso práctico: sliders
Podemos utilizar variables CSS para dar estilo a los sliders (input type=range
). Todavía necesitamos JavaScript, pero las variables simplifican mucho el código. Veamos como.
El HTML
En el HTML tengo un slider que puede tomar valores desde 0 hasta 100. El valor actual value = "50"
.
<input type="range" min="0" max="100" value="50">
El JavaScript
En JavaScript utilizamos el método setProperty()
para recuperar el valor del slider ( input.value
) y guardar este valor en una variable CSS que llamamos --value
.
var input = document.querySelector("input[type=range]");
input.style.setProperty("--value", input.value);
El evento "input"
se dispara en seguida que el valor de un elemento <input>
cambia. Podemos aprovechar este evento para cambiar el valor de la variable --value
cada vez que el usuario mueve el cursor ( thumb ) del slider.
input.addEventListener("input", function(evt) {
input.style.setProperty("--value", input.value);
},false);
El CSS
Sabemos que un gradiente de color es una transición suave y progresiva entre dos o más colores. No tiene por que ser así. Podemos conseguir límites tajantes utilizando color-stops
situados muy cerca el uno del otro.
Para dar estilo al "track" o la barra de desplazamiento del slider vamos a crear un gradiente lineal de izquierda a la derecha ( to right
), de HotPink
a negro.
Si por ejemplo el valor del atributo value = "50"
( el cursor se encuentra justo en el medio del slider ) tenemos que poner esta regla en el CSS para crear un limite claro al 50%:
background-image:linear-gradient(to right, HotPink 50%, black 50%));
Un pequeño secreto:
Si en un gradiente la posición del segundo color-stop
es menor que la posición del primer color-stop
, el CSS considera que la posición del segundo color-stop
coincide con la posición anterior, y por lo tanto crea un límite tajante. Así que podemos escribir:
background-image: linear-gradient(to right, HotPink 50%, black 0));
Esto crea un gradiente lineal de izquierda a la derecha ( to right
), de hecho una imagen ( background-image
) mitad HotPink
mitad negro.
Pero necesitamos que el limite del gradiente coincida siempre con la posición del thumb ( o el control del slider ). Para esto, en lugar de 50% vamos a utilizar el valor del atributo value, que hemos guardado en una variable CSS llamada --value
.
Pero --value
es un numero y la sintaxis nos pide un porcentaje. La solución es utilizar el método calc() y multiplicar la variable var(--value) * 1%
.
background-image: linear-gradient(to right, HotPink calc(var(--value) * 1%), black 0));
Así es como queda el código:
input[type=range]{ width:20em; height:.5em; display:block; margin:5em auto; -webkit-appearance: none; /*en los navegadores de tipo -webkit- anula los estilos con los cuales los sliders vienen de fabrica.*/ background-image:linear-gradient(to right, HotPink calc(var(--value)*1%), black 0); }
See the Pen Input type range + CSS vars # 0* by Gabi (@enxaneta) on CodePen.
Esta vez hemos tenido suerte. Pero no siempre los sliders tienen valores de 0 a 100. Probemos a utilizar un slider diferente.
<input type="range" min="30" max="170" step="1" value="90">
Las cosas ya no cuadran. El valor 50 ya no cae en el medio del slider. Así que en el javascript tenemos que recalcular la posición de los color-stop
en función del valor de los atributos min
y max
del input:
var inputMin = input.getAttribute("min"); var inputMax = input.getAttribute("max"); var unidad = (inputMax - inputMin) / 100; input.style.setProperty("--value", (input.value - inputMin)/unidad);
Y para no repetir todo este código dos veces lo voy a poner en una función:
function actualizarInput(input) { var inputMin = input.getAttribute("min"); var inputMax = input.getAttribute("max"); var unidad = (inputMax - inputMin) / 100; input.style.setProperty("--value", (input.value - inputMin)/unidad); }
Véalo en codepen:
See the Pen Input type range + CSS vars #1* by Gabi (@enxaneta) on CodePen.
¡Pero no es así como se hace!
Claro que no. de hecho lo que tenemos que hacer es dar estilo a la barra de desplazamiento ( track ), y no a todo el slider.
Recuerde que para dar estilo al track
utilizamos estas otras reglas de estilo:
input[type=range]::-webkit-slider-runnable-track{} input[type=range]::-moz-range-track{}
I en este caso utilizamos el gradiente que hemos creado antes como imagen de fondo para la barra de desplazamiento del slider:
input[type=range]::-webkit-slider-runnable-track { height: 3px; background:linear-gradient(to right, HotPink calc(var(--value)*1%), black 0); } input[type=range]::-moz-range-track { height: 3px; background:linear-gradient(to right, HotPink calc(var(--value)*1%), black 0); }
See the Pen Input type range + CSS vars #2* by Gabi (@enxaneta) on CodePen.
De paso he añadido una etiqueta <label>
donde poner el valor del slider, y dos líneas de código en el JavaScript para actualizar el innerHTML
de la etiqueta cada vez que se dispara el evento "input"
.
function actualizarInput(input){
var label = input.parentElement.querySelector("label");
label.innerHTML = input.value;
var inputMin = input.getAttribute("min");
var inputMax = input.getAttribute("max");
var unidad = (inputMax - inputMin) / 100;
input.style.setProperty("--value", (input.value - inputMin)/unidad);
}
Dos o más sliders
Muchas veces tenemos más de un slider en cada página. Para tomar esto en consideración necesitamos modificar el JavaScript por tal de iterar sobre todos los sliders de la página. Y no es nada complicado. Utilizamos la sentencia for...of para iterar sobre todos los sliders de la página.
for( input of document.querySelectorAll("input[type=range]")){ actualizarInput(input); }
A continuación utilizamos el evento input
para modificar el estilo de cada slider. Para apuntar a todos los sliders aplicamos addEventListener
al documento ( document.addEventListener
) y para precisar cual de los inputs escucha al evento en un determinado momento utilizamos var input = evt.target
. ( donde target
= objetivo, meta; y evt
representa al evento – "input"
en este caso )
document.addEventListener("input", function(evt) { var input = evt.target; actualizarInput(input) });
See the Pen Input type range + CSS vars #3 by Gabi (@enxaneta) on CodePen.
Misión cumplida en 17 líneas de código JavaScript.