Burbujas de valores para entradas de rango
Las entradas de rango en HTML son así:
input type="range" name="quantity" min="1" max="10"
En los navegadores que los admiten, se ven así:
Eso es genial y todo. Puede usarlo para cualquier cosa en la que desee recopilar un número de un usuario que tenga un valor mínimo y máximo obligatorio.
¿Pero notas algo extraño? Por sí sola, esa entrada de rango no comunica al usuario qué número realmente enviar. Ahora bien, si tu opinión es algo como “¿Cómo te sientes? A la izquierda por triste, a la derecha por feliz”. – entonces está bien, probablemente no necesites mostrarle un número al usuario. Pero apuesto a que es más común que necesites mostrar el número que no mostrarlo.
Para ser justos, la especificación dice:
El elemento de entrada representa un control para establecer el valor del elemento en una cadena que representa un número, pero con la advertencia de que el valor exacto no es importante , lo que permite que los UA proporcionen una interfaz más simple que para el estado Número .
Pero vamos, sólo porque queremos un control deslizante interesante no significa automáticamente que debamos evitar que el usuario conozca el valor enviado. No sería necesario que los navegadores deban alterar el control de su interfaz de usuario para mostrar ese número. ¡Estoy diciendo que deberíamos construirlo nosotros mismos!
Este es el caso de uso perfecto para la output
etiqueta, que es específicamente para valores calculados por elementos de formulario. Aquí hay una implementación súper simple de cómo puedes usarla:
input type="range" name="foo"output for="foo" onforminput="value = foo.valueAsNumber;"/output
¡Actualizar! Nueva versión con Vanilla JavaScript que también funciona mejor.
Nuestro objetivo aquí es mostrar una “burbuja” que muestre el valor actual de una entrada de rango.
Establecer el valor de nuestra “burbuja” a partir del valor de la entrada es cuestión de extraer el valor del rango y colocarlo en la burbuja:
range.addEventListener("input", () = { bubble.innerHTML = rangel.value;});
El truco consiste en colocar la burbuja a lo largo de la entrada del rango de modo que se deslice junto al “pulgar”. Para hacer eso, necesitaremos calcular porcentaje qué de la burbuja debe desplazarse hacia la izquierda. Entonces, creemos una función para hacer eso y mantener las cosas un poco más limpias:
range.addEventListener("input", () = { setBubble(range, bubble);});function setBubble(range, bubble) { const val = range.value; const min = range.min ? range.min : 0; const max = range.max ? range.max : 100; const newVal = Number(((val - min) * 100) / (max - min)); bubble.innerHTML = val; // Sorta magic numbers based on size of the native UI thumb bubble.style.left = newVal = "%";}
Aquí nos aseguramos de tener en cuenta los atributos mínimos y máximos de las entradas del rango y calculamos una posición porcentual entre 0 y 100 en función del valor actual en ese rango. No todos los rangos son los números predeterminados de 0 a 100, por lo que digamos que un rango tenía el valor 50 en un rango de 0 a 200, eso sería el 25% del camino. Esto explica eso.
Pero tiene un defecto molesto: la burbuja está demasiado a la izquierda al principio y demasiado a la derecha al final. En las entradas de rango, el pulgar no cuelga del borde izquierdo, por lo que su centro está al principio y lo mismo al final. Como una barra de desplazamiento, los bordes del pulgar se detiene dentro de la pista.
Podemos usar algunos números mágicos que parecen funcionar bastante bien en todos los navegadores:
// Sorta magic numbers based on size of the native UI thumb bubble.style.left = `calc(${newVal}% + (${8 - newVal * 0.15}px))`;
Aquí está la demostración final:
Me inspiré para explorar esto porque el lector MaxGloba escribió su versión, que publicaré aquí:
Un aspecto interesante de la versión de Max es que la entrada de rango tiene estilo CSS, por lo que se conoce el tamaño exacto del pulgar. Hay algunos números que parecen bastante mágicos en las matemáticas de JavaScript, pero al menos se basan en números reales establecidos en CSS del tamaño del pulgar.
Otras versiones
Dave Olsen portó la idea (original) de no depender de jQuery. Aquí está esa versión:
Sean Stopnik:
simurái:
Vicente Durand:
No olvide que la entrada de rango puede tener listas de datos que les ponen pequeñas muescas, lo cual es genial.
Ana Tudor tiene una colección enorme, muchas de las cuales indican el valor actual a través de su diseño.
? Versión anterior de la versión original de esta publicación (jQuery, además no funciona tan bien)
Dejo esto aquí por razones históricas.
Incorporemos a nuestro amigo jQuery y activemos nuestro CSS. Este objetivo está a continuación. Cualquier entrada de rango, en cualquier momento, cualquier mínimo/máximo/paso: colocamos una burbuja encima que muestra el valor actual.
Primero diseñemos el elemento de salida. Lo colocaremos absolutamente encima de la entrada. Eso también nos da la posibilidad de ajustar el valor izquierdo, una vez que determinemos con JavaScript cuál debería ser. Lo mejoraremos con degradados y radio de borde, e incluso agregaremos un pequeño triángulo de puntero con un pseudoelemento.
output { position: absolute; background-image: linear-gradient(top, #444444, #999999); width: 40px; height: 30px; text-align: center; color: white; border-radius: 10px; display: inline-block; font: bold 15px/30px Georgia; bottom: 175%; left: 0; margin-left: -1%;}output:after { content: ""; position: absolute; width: 0; height: 0; border-top: 10px solid #999999; border-left: 5px solid transparent; border-right: 5px solid transparent; top: 100%; left: 50%; margin-left: -5px; margin-top: -1px;}
Ahora lo que tenemos que hacer es observar todas las entradas de rango para detectar un cambio en su valor. Nuestro objetivo es cambiar la posición izquierda de la burbuja al ritmo del control deslizante. Eso no es lo más simple del mundo, ya que los controles deslizantes pueden tener cualquier ancho y cualquier valor mínimo o máximo. Tendremos que hacer un poco de cálculo. Aquí está todo el JavaScript jQuery, comentado:
// DOM Ready$(function() { var el, newPoint, newPlace, offset; // Select all range inputs, watch for change $("input[type='range']").change(function() { // Cache this for efficiency el = $(this); // Measure width of range input width = el.width(); // Figure out placement percentage between left and right of input newPoint = (el.val() - el.attr("min")) / (el.attr("max") - el.attr("min")); // Janky value to get pointer to line up better offset = -1.3; // Prevent bubble from going beyond left or right (unsupported browsers) if (newPoint 0) { newPlace = 0; } else if (newPoint 1) { newPlace = width; } else { newPlace = width * newPoint + offset; offset -= newPoint; } // Move bubble el .next("output") .css({ left: newPlace, marginLeft: offset + "%" }) .text(el.val()); }) // Fake a change to position bubble at page load .trigger('change');});
La única parte bruta que hay es ese 1.3
valor. Estaba intentando alinear la punta del triángulo de la burbuja con el centro del control deslizante. No es fácil, porque el centro del control deslizante nunca está 100% hacia la izquierda o hacia la derecha. Ese valor no es perfecto ni está perfectamente implementado, pero es mejor que no tenerlo.
Como beneficio adicional, los navegadores que no admiten la entrada de rango aún obtienen la acción de burbuja.
El código anterior depende de que las entradas de rango tengan un min
valor especificado max
. Si no lo hacen, se rompe un poco. Creo que sería extraño usar una entrada de rango sin especificar estas cosas, aunque si no lo haces parece que por defecto son 0 y 100. Para proteger esto, tomarías cada atributo, lo probarías y, si así fuera, no lo harías. No se ve bien, arréglalo. Algo como:
var minValue, maxValue;if (!el.attr("min")) { minValue = 0; } else { minValue = el.attr("min"); }
…luego usa la minValue
variable en las matemáticas. Y haga lo mismo para máx. De todos modos, aquí está la demostración en vivo:
Deja un comentario