Javascript con Furoya: averiguar tamaños y pasar su valor a Css. Caso de uso: coloreado del scroll 4.10.15
Esta nueva entrega sobre Javascript de Furoya está dedicada a colorear las barras de scroll usando Js para calcular al píxel sus dimensiones y aplicar filtros Css que sólo afecten a ellas y no al resto de contenidos.
Javascript con Furoya: averiguar tamaños y pasar su valor a Css. Caso de uso: coloreado del scroll
Este artículo será un poco extraño. Les cuento por qué.
Originalmente la demo fue pensada para publicarse en Codepen, como una versión más acabada de un viejo experimento que hicimos paralelamente con Kseso : colorear las scrollbars de Firefox.
El mecanismo es conocido por los veteranos de guerra que combatimos con Internet Explorer 5.5, que habilitaba de manera propietaria el cambio de color en las barras, pero necesitaba de un filtro de color para el efecto que le ponía un diseño, imagen y hasta texto detrás de su trackbar o de su botón deslizable.
Para Mozilla (también anda en webkit, pero no lo necesitamos) hace falta un filtro Css o modo de fusión CSS que mezcle los colores de una scrollbar con una capa "de fondo" que tiene el color que nos interesa. La mayor dificultad para la hoja de estilos es que la capa (elemento, borde, imagen, color o gradiente de fondo, ...) debe tener el grosor exacto de la barra de desplazamiento; porque de otra forma la mezcla se verá también sobre el contenido de su caja.
Todavía no encontré cómo medir ese grosor en CSS, y no vamos a usar "números mágicos"; las barras son configurables por el usuario y que la mayoría de la gente no las modifique no quiere decir que en todo el mundo sea igual. Si queremos hacer las cosas bien, hay que medirlas.
Para eso sirve javascript, que una vez calculado el valor se lo pasa a los estilos del documento. Y ese 'paso' se puede hacer de varias maneras distintas.
Entonces surgió este artículo. Ya no son tan importantes las scrollbars con color en Firefox sino los modos de calcular medidas en el documento y cómo volcarlas a la hoja de estilos.
Para empezar, les dejo la versión original, que solamente muestra que de alguna manera es posible el efecto de colorizado, aunque sea poco práctico.
See the Pen CSS Scrollbar Color in Firefox. (Experimental) by solipsistaCP (@solipsistacp) on CodePen.
CSS Scrollbar Color in Firefox. (Experimental).
Cálculo de los tamaños de las barras de scroll con Js
Para continuar, una tabla interactiva que hice años atrás, y que actualicé para responder una duda de nuestro amigo Manuel Rosendo Castro Iglesias. Measures: browser and document.. (Sugiero reducir el zoom hasta ver la tabla completa antes de desplazar o redimensionar el documento. Los códigos para cada medición se ven haciendo un click en su descripción.)
Y una vez que hayan estudiado un poco estos antecedentes, vemos esa segunda versión de la que hablaba al comienzo, que tiene texto en inglés, porque como ya adelanté fue pensada como una demo y no como parte de este artículo.
See the Pen CSS Scrollbar Color in Firefox. (Another Experiment) v2.1 by solipsistaCP (@solipsistacp) on CodePen.
De todos los modos posibles para pintar las barras, elegí el de ponerlas con su caja dentro de un contenedor, y a éste darle bordes derecho e inferior con el color de mezcla. A esos bordes hay que ponerles el tamaño exacto de las scrollbars y ubicarlos (de manera absoluta) justo detrás de la vertical y la horizontal, respectivamente.
Con un mix-blend-mode: multiply
que afecte toda la caja (incluyendo las barras) y usando a white
como color de fondo (que no alcanza a las barras y no hace una mezcla perceptible en el contenido), ya tenemos el efecto que buscamos.
Inserción de los valores en los estilos
Pero nos queda el motivo para traer todo esto aquí. Hay que calcular tamaños, y pasarlos al CSS. El detalle del JS con algunos comentarios es éste.
<script type="text/javascript">
function pinta() {
contrasteV = "lime"; //VERTICAL SCROLLBAR COLOR
contrasteH = "fuchsia"; //HORIZONTAL SCROLLBAR COLOR
cajaColoreada = document.querySelector(".contenido1");
//AVAILABLE WIDTH IN PX (WITHUOT SCROLLBARS, PADDING,...)
anchoCliente = cajaColoreada.clientWidth;
//AVAILABLE HEIGHT IN PX
altoCliente = cajaColoreada.clientHeight;
//TOTAL WIDTH IN PX
anchoTotal = cajaColoreada.offsetWidth;
//TOTAL HEIGHT IN PX
altoTotal = cajaColoreada.offsetHeight;
//THICKNESS OF BAR
grosorBarras = anchoTotal - anchoCliente;
cajaColoreada.style.width = anchoTotal +"px";
cajaColoreada.style.height = altoTotal +"px";
cajaColoreada.parentElement.style.borderRight = "solid "+ grosorBarras + "px " + contrasteV;
cajaColoreada.parentElement.style.borderBottom = "solid "+ grosorBarras + "px " + contrasteH;
cajaColoreada.parentElement.style.width = (anchoTotal - grosorBarras) + "px";
cajaColoreada.parentElement.style.height = (altoTotal - grosorBarras) + "px";
}
onload = pinta;
</script>
Unos apuntes a este script
- De psicodélico que soy, hice una barra de cada color. Obviamente no es indispensable, pero para eso sirven las dos primeras variables. La tercera contiene la referencia a la caja que vamos a colorear. Y a partir de allí empezamos a sacar cuentas.
- La manera más fácil de saber qué grosor tiene una scrollbar, es medir el ancho total de su caja (
offsetWidth
) y restarle su ancho disponible (clientWidth
). Si no haypadding
,border
o similares, lo que queda es la medida que buscamos. - En el ejemplo capturamos también las medidas de altura, porque todas nos van a servir para posicionar y dimensionar la caja contenido en su caja contenedora. Y todas son devueltas como números absolutos; aunque están en pixeles javascript no incluye la unidad, así que es simple hacer las cuentas, pero al pasarlos al CSS hay que recordar agregarles el "px".
- Lo primero es fijar ancho y alto de la caja contenido, que serán las medidas puestas por el CSS original. Si hay alguna en porcentajes u otra medida relativa, ahora se hacen absolutas y en pixeles como estilos inline.
- Luego se le da a su contenedor (
parenElement
) un borde sólido derecho y otro inferior, y se les pasa la medida calculada del grueso de la scrollbar, además del color que metimos en la variable correspondiente. - A partir de acá, el contenedor va a ser más grande de lo necesario porque le sobran los bordes, así que se le reduce el tamaño "un grosor de scrollbar de ancho y uno de alto" para que vuelva a su medida original. (Nota: supongo que esto se podría resolver con
box-sizing
en el CSS, pero yo tenía ganas de hacer más cuentas).
Los métodos para agregar estilos en línea ya son viejos conocidos, no insisto con ellos. Lo que sí voy a recordar es algo mencionado más arriba : las medidas relativas de los elementos son capturadas por JS y devueltas en pixeles. Eso significa que una vez ejecutado el escript ya no hay ajuste por redimensionado de la ventana del navegador. Lo pueden probar pasando el código a un documento, y verán que para lograr el ajuste tienen que recargar la página.
Segunda versión mejorada
Por eso, vamos a hacer una versión del ejemplo previo que sí se ajusta en ancho (el alto era fijo para el contenedor, y su contenido siempre estaba al 100%).
See the Pen CSS Scrollbar Color in Firefox. (Another Experiment) v2.2 by solipsistaCP (@solipsistacp) on CodePen.
En el código encontramos algo de lo que veremos extensamente más abajo. Otro modo de leer y asignar formatos ya no en línea sino directamente sobre la hoja de estilos.
anchoDeclaradoCSS = document.styleSheets[0].cssRules[4].style.width
En esa variable vamos a guardar el valor sacado del documento, de su hoja de estilo con ítem cero (la primera y única, para el caso), de su regla con ítem cuatro (si las cuentan en el CSS, es .contenedor {...}
) y de su estilo para width
. Ese valor es "40%", y como ya no es medido sino extraído, vale realmente "40%".
Ahora que sabemos cuánto es el porcentaje que se debe ajustar, vamos a poner otra vez los valores inline, pero aprovechando calc()
para sumarle o restarle el valor en pixeles de las barras.
cajaColoreada.style.width = "calc(100% + "+grosorBarras+"px)";
cajaColoreada.style.height = "calc(100% + "+grosorBarras+"px)";
...
cajaColoreada.parentElement.style.width = "calc("+anchoDeclaradoCSS+" - "+grosorBarras+"px)";
...
Además, agregamos un evento para que el escript se ejecute no sólo al cargar, sino también al redimensionar. En realidad, hasta podríamos evitarlo y hacer más eficiente el código separando en dos funciones la toma de medidas y su aplicación, pero no quise hacer los ejemplos tan diferentes para que se puedan comparar más facilmente.
Ahora vamos a ver una forma más recomendable para pasar formatos, modificando la hoja de estilos. El método que usamos arriba para leer el ancho en porcentaje tiene su versión para insertar selectores con sus propiedades y valores.
See the Pen CSS Scrollbar Color in Firefox. (Another Experiment) v3.0 by solipsistaCP (@solipsistacp) on CodePen.
Y aquí vemos el detalle para el nuevo código.
document.styleSheets[Índice de la hoja de estilo].cssRules[Índice del selector].style.Propiedad para leer valor;
document.styleSheets[Índice de la hoja de estilo].insertRule(Selector{Propiedad : Valor}, Índice de la nueva regla);
El Índice de la hoja de estilo en nuestras pruebas es [0]
, pero si existe más de una en el documento hay que apuntarle a la que queremos leer o cambiar.
El Índice del selector se usa igual, contamos a partir de cero hasta el que nos interesa conocer y después JS lee con style.Propiedad
su valor como cadena de texto, tal como lo interpreta el navegador.
La forma de agregar reglas es también sencilla, pero insertRule("","")
ya tiene 2 parámetros; hay que escribir la declaración igual que en CSS y además la posición que ocupará entre las demás que tenga el selector; una vez ubicada, "empuja" a las siguientes hacia abajo.
Supongamos que tenemos
h1 { /*índice 0*/
font: 3em/1 arial, serif;
}
h2 { /*índice 1*/
font: 2em/1 arial, serif;
}
h4 { /*índice 2*/
font: .5em/1 arial, serif;
}
y si con javascript queremos agregar el h3
en orden así
...
document.styleSheets[0].insertRule(h3{font: 1em/1 arial, serif; }, 2);
...
El CSS final quedaría
h1 { /*índice 0*/
font: 3em/1 arial, serif;
}
h2 { /*índice 1*/
font: 2em/1 arial, serif;
}
h3 { /*índice 2*/
font: 1em/1 arial, serif;
}
h4 { /*índice 3*/
font: .5em/1 arial, serif;
}
Pues bien, en el código que venimos estudiando el segundo parámetro no está como un número. Y hay una buena razón para ello.
Resulta que cssRules.length
devuelve la cantidad de reglas que hay en la hoja de estilos, y como ya vimos, si hay (por ejemplo) 10 reglas éstas se iteran de 0 a 9. Entonces usarlo como número de ítem es la mejor forma de asegurarnos que la nueva propiedad sea siempre la última, y si repetimos un selector las reglas que contenga van a "pisar" o completar las del anterior.
Y como no hay dos sin tres...
Y ya que hablamos de "pisar", vamos a ver un último método. Es lamentable, nadie lo recomienda, pero funciona y más de una vez nos puede sacar de un apuro facilmente.
Hemos probado anteriormente que es posible leer y escribir el contenido de un elemento en el body
usando textContent
o innerHTML
. De la misma forma que ponemos la regla como cadena de texto en insertRule
, también podemos hacerlo para innerHTML
; y luego insertarlo en un elemento <style>
que esté ya no en el head
sino en el cuerpo del documento.
See the Pen CSS Scrollbar Color in Firefox. (Another Experiment) v4.0 by solipsistaCP (@solipsistacp) on CodePen.
Como es evidente, document.body.getElementsByTagName("style")[0].innerHTML
sirve para insertar (o leer) un contenido HTML en el primer elemento con etiqueta style
que se encuentre en el body
; y en el código hay uno puesto justo al comienzo, pero que está después del que tenemos en el head
, y por eso sus reglas tienen prioridad y reemplazan o completan a las anteriores.
Como dato final, digamos que todo el desarrollo está pensado para Mozilla Firefox, ya que la excusa eran sus scrollbars. En Internet Explorer se usan otros métodos para modificar estilos, pero son fáciles de encontrar en distintos tutoriales. Una vez que se manejen cómodos con estos, aprender los de IE se hace muy simple.
Autoría
Artículo original de Furoya.
La intención del autor con sus colaboraciones no es que los artículos sirvan para hacer un copy&paste de códigos sino que comprendas y aprendas la lógica y el cómo trabaja javaScript.
Y a partir de lo expuesto experimentes tú.
El autor del post y el editor del blog te animamos a que plantees tus dudas o reflexiones y que compartas tus realizaciones en base a lo expuesto en los comentarios. Recuerda que puedes incluir pens (ejemplos en Codepen.io) en ellos.