soy Kseso y esto EsCSS

Javascript desde cero: background-image aleatorio. por Furoya

Javascript desde cero: background-image aleatorio. por Furoya

✎ 16
COLABORACIÓN AUTOR INVITADO
Javascript desde cero: background-image aleatorio. por Furoya

Preámbulo:

El CSS ha crecido mucho. Alguno diríamos que demasiado.
De un puñado de instrucciones para dar formato a documentos varios (el *.HTML encabeza la lista, pero no fue ni será el único) hoy nos encontramos con algo demasiado parecido a un lenguaje de programación.

Y eso muchas veces termina confundiendo a quienes comienzan a usar estilos con animaciones, mediaquerys o selectores avanzados, porque les da la impresión de que realmente es un lenguaje de programación.

Algo que no ayuda, es que en blogs como éste el autor haga brujerías y consiga con estilos muchos efectos que ya son difíciles de lograr hasta con javascript.

Por eso todos los que frecuentamos el sitio ya no nos sorprendemos con consultas del tipo ¿Cómo pongo la fecha del día al comienzo de mi documento?. Ni siquiera podemos quejarnos demasiado, porque el W3C nos está dejando sin argumentos : una regla para pseudoelementos, o hasta un elemento HTML5 ad hoc deberían tener prevista una solicitud así.

Pero mientras no lo haga, hay que terminar en verdaderos lenguajes de programación, que no solamente tienen acceso a datos sobre el navegador, la fecha, el mismo documento ... sino que pueden devolver un valor para después reescribir con él una regla CSS, o un valor HTML.

El punto es que muchos diseñadores optan para dar una mejor presentación a sus trabajos por libraries o código prehecho al que sólo hay que cambiarle unos parámetros; algo que les resulta más familiar viniendo del CSS. Pero resulta que PHP y javascript tienen mucho código realmente simple de manejar, con funciones ya cargadas que evitan agregar archivos externos aumentendo el peso final. Y son especialmente útiles para obtener esos valores que CSS calcula, pero no muestra.

Ésa es la intención de este artículo: presentar funciones nativas que puedan agregar operatividad a los estilos de una página usando javascript (que trabaja sobre el navegador y ve lo que cada usuario) de una manera que a cualquier programador le termine erizando los cabellos de la nuca, pero que —espero— sean accesibles a quienes no estén acostumbrados a manejarse con lenguajes lógicos.

Después de esta muy larga introducción, vamos a un caso práctico.

El comentario que me convenció para escribirle a Kseso sobre este asunto fue uno hecho por Fabian Jofre donde planteó una imagen aleatoria cada vez que se cargue el documento.

Números al azar o aleatorios

Empecemos por decir que lo primero que necesitamos es un número al azar (o que al menos sea diferente) cada vez que abramos el documento. Y que ese número esté asociado al nombre de una imagen (algo que excede al CSS, JS y HTML, porque hay que crear la imagen y nombrarla con un número). Vamos a ocuparnos de lo primero.

Como no quiero que estos ejemplos se usen como cut&paste sino que sirvan para entender cómo trabajan y después cada uno de los lectores siga investigando por su cuenta, me voy a extender un poco en las explicaciones.

Para empezar, hay que crear un área de trabajo en el documento, y como para generar un valor numérico aleatorio vamos a usar javascript, debemos crear el elemento que lo contenga. Se hace con etiquetas <script>...</script> y sus correspondientes atributos:

<script type="text/javascript"> </script>

que por lo general están dentro del <head></head>

Objetos Math.

Bien, javascript tiene para trabajar con cálculos matemáticos una serie de objetos Math.algo, y uno de los que vamos a ocupar ahora es Math.random(). Lo que hace es capturar del reloj de la máquina su valor básico, que es la cantidad de milisegundos desde la medianoche del 1º de enero de 1970 hasta la fecha.

Como cada vez que lo pidamos van a pasar unos segundos, siempre nos va a aparecer uno distinto; y con eso se simula que es un valor aleatorio. En realidad, es pseudoaleatorio, lo podemos decir ahora que conocemos el truco.

Cada navegador hace un cálculo con este valor para entregarle a Math.random() un número positivo, decimal, igual o mayor que cero y siempre menor que uno. El motivo lo vemos unos párrafos más abajo. Primero vamos a probarlo en un documento.

<script type="text/javascript"> Math.random(); </script>

Y no vemos nada. Así como existe una consola para inspeccionar el HTML y el CSS, también tenemos en los navegadores una para javascript. Pero para no complicarnos la vida, vamos a aprovechar que JS puede generar mensajes modales, y le decimos que lo muestre, por ejemplo, en uno de alerta.

<head> <script type="text/javascript"> alert( Math.random() ); </script> </head>

¿Y cómo sabemos que va a cambiar con el paso de los milisegundos? Una manera es poner varios, ya que al aparecer el primer mensaje, nos vamos a detener a mirarlo unos segundos, lo vamos a cerrar, y recien entonces el navegador va a "pedir" el siguiente Math.random() para mostrarlo. Y así con cada uno.

<head> <script type="text/javascript"> alert( Math.random() ); alert( Math.random() ); alert( Math.random() ); </script> </head>

Aquí ya aparecen dos problemas, uno es que si tenemos guardadas una serie de imágenes como "imagen0.png", "imagen1.png", ..., "imagen9.png", "imagen10.png", ese número random no nos sirve. Hay que convertirlo en uno que coincida con nuestras imágenes.

Si tenemos 20 (desde "imagen0.png" hasta "imagen19.png") nos tiene que mostrar un número entre 0 y 19. Y esto se hace fácil, como nuestro random es menor que 1 (¿se acuerdan?) al multiplicarlo por cualquier número siempre va a dar como resultado otro número menor.

10 * 0.5 = 5 25 * 0.4 = 10 2 * 0.4 = 0.8 1234 * 0 = 0

Entonces, si tenemos 20 imágenes y multiplicamos 20 por nuestro valor al azar, siempre nos va a resultar un número del 0 al 19.999… . La cuenta se escribe así:

<head> <script type="text/javascript"> alert( Math.random() * 20 ); alert( Math.random() * 20 ); alert( Math.random() * 20 ); </script> </head>

Eliminando decimales

Ahora debemos resolver otro problema. Los números casi siempre van a aparecer con decimales, y nosotros necesitamos enteros. Y para eso javascript tiene más Math.algo que nos ahorran los cálculos. Math.floor() elimina los decimales redondeando hasta el "piso" (para abajo).

Estas funciones se encadenan con puntos, o se aplican a lo que lleven dentro de los paréntesis, como parámetros. como Math.random() no tiene parámetros, adentro nunca va nada; pero toda la operación para tener nuestro rango de números sí se manda como parámetro de Math.floor() para que el navegador sepa a qué le tiene que quitar los decimales para abajo.

<head> <script type="text/javascript"> alert( Math.floor( Math.random() * 20 ) ); alert( Math.floor( Math.random() * 20 ) ); alert( Math.floor( Math.random() * 20 ) ); </script> </head>

Ya estamos cerca, y a estas alturas ya se dieron cuenta de que es más lo que estoy explicando que lo complicado del código. Tenemos generado al azar un número que coincide con nuestra lista de fotos, pero no con el nombre completo.

Aplicar los valores aleatorios en estilos

Vamos a ver el HTML.

<!DOCTYPE html> <html lang="es-ar"> <head> <meta charset="utf-8" /> <title></title> <style type="text/css"> figure { width: 640px; height: 480px; border: solid 1px navy; background-image: url(imagenDefault.png); /*default*/ background-size: cover; } </style> </head> <body> <figure></figure> </body> </html>

Javascript no se usa solamente para hacer cuentas, también puede modificar al vuelo el código HTML y escribirle atributos a los elementos. Como un style="background-image:url()" que siempre va a pesar más que el de la hoja de estilos. Pero antes debemos crear el texto de ese valor que coincida con nuestras imágenes. Y es muy fácil, ni requiere explicación.

<head> <script type="text/javascript"> alert( "imagen" + Math.floor( Math.random() * 20 ) + ".png" ) </script> </head>

Cabe señalar que el signo de suma + tiene un doble uso:

  1. si estamos trabajando con números, los suma
  2. pero si trabajamos con cadenas de texto, los concatena.

Y la mayoría de las veces javascript interpreta los números como caracteres y no como valores numéricos. Si hay algún texto por medio, automaticamente los vuelve texto también, aunque originalmente hayan sido números. Ahora no nos afecta (al contrario) pero recuerden este detalle cuando el día de mañana quieran sumar 2+2 y les dé como resultado "22". Algún "2" será texto...

Ya tenemos el nombre correcto de la imagen aleatoria, y tenemos que meterla como parámetro de la función CSS url(). El mecanismo es el siguiente, sacando el mensaje de alerta del código de ejemplo anterior y aplicado a un elemento:

<!DOCTYPE html> <html lang="es-ar"> <head> <meta charset="utf-8" /> <style type="text/css"> figure#cambiado { width: 640px; height: 480px; border: solid 1px navy; background-image: linear-gradient(to bottom, #444, #000); /*default*/ background-size: cover; } </style> </head> <body> <figure id=cambiado></figure> <script type="text/javascript"> document.querySelector("figure#cambiado").style.backgroundImage = "url(imagen" + Math.floor( Math.random() * 20 ) + ".png)"; </script> </body> </html>

El resultado final puedes verlo en el siguiente pen. Recárgalo con el botón de Rerun que aparece al poner el cursor sobre él.

See the Pen GgMEjR by Kseso (@Kseso) on CodePen.

Ver Demo

Ok. Vamos a explicar las "cosas raras". El escript ya no está en el head, porque como vimos javascript (y html) se van ejecutando a medida que se cargan (¿recuerdan que cada alerta mostraba un número distinto, a medida que se iban disparando en orden de "escritura"?). Si ponemos el escript que busca el elemento con nombre figure e identificador único o id cambiado antes de que el navegador lo escriba en el documento, obviamente no lo va a encontrar. Primero dejamos que lo muestre, y después lo modificamos con javascript.

La lógica para escribir esa instrucción que edita a
<figure id="cambiado" style="background-image:url(imagen4.png)"></figure>
es que todo lo que sea el texto del valor va entre comillas. Lo que cambia es el número, que se lo concatenamos en su lugar usando los signos de suma (los espacios fuera de las comillas se ignoran). Y la sintaxis se lee de la siguiente manera:

en el documento se busca el elemento que coincida con el selector CSS figure#cambiado y se le aplica un estilo inline (en el atributo html style) de background-image con valor url(imagen seguido del número generado con nuestras funciones javascript y terminando con la cadena .png).

Javascript tiene una característica por lo que la mitad de los programadores lo aman, y la otra mitad lo odia. Para lograr un mismo objetivo hay chorrocientas maneras distintas. Ésta es sólo una, y me quedé con las ganas de incluir variables, pero ya hubiese sido un artículo muy largo. ;-)

Notas para jugar con estos códigos

  1. Crea tantas imágenes como necesites mostrar
  2. Asigna la misma extensión y el mismo nombre de archivo a cada imagen, cambiando sólo el numeral final de cada una: mipic0.jpg / mipic1.jpg /.../ mipic99.jpg
  3. En la sintaxis "url(imagen" + Math.floor( Math.random() * 20 ) + ".png)"; has de cambiar:
    • la cadena textual "url(imagen" por la cadena que corresponda a la ruta a tus imágenes (nombre común de todas ellas) menos el número y extensión del archivo: "url(http://dominio.ext/ruta/carpeta/imagen"
    • el valor 20 por el número total de imágenes que hayas preparado.
    • el valor ".png)" por la extensión o formato de tus imágenes.

Autoría

Furoya: Autor del artículo

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.
La imagen que encabeza el artículo las usadas en el pen de la demo de publicdomainreview.org