Javascript desde cero: background-image aleatorio. por Furoya

La intención de este artículo es presentar funciones nativas de JS que puedan agregar operatividad a los estilos de una página usando javascript 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.

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

Comentarios: 16

  1. hola!! muy bueno las explicaciones pero tengo una duda no consigo que me funcione el codigo :/
    todo el codigo lo pones en el mismo archivo html?

    ResponderEliminar
    Respuestas
    1. Hola Mclaren
      Si te refieres al pen de la demo, sí.
      Tanto el código Html, como Css y javascript necesarios están en ella.

      Un saludo

      Eliminar
    2. gracias por la pronta respuesta, esto es lo que he hecho:

      https://onedrive.live.com/prev?cid=ae57e5501c210650&id=AE57E5501C210650%21159171&v=TextFileEditor

      podrias porfavor echarle un vistazo
      no consigo saber porque no sale :/ me podrias echar una mano?

      Eliminar
    3. Hola Mclaren.
      ¿Seguro esas rutas están bien? Porque en el ejemplo (que podrías poner en Codepen o similar para que lo viésemos) no hay rutas absolutas, así que ni eso nos dejás probar.

      El Código es demasiado sencillo, no hay forma de no conseguir saber por qué no sale.
      Cualquier consola te avisa si escribiste un paréntesis o un espacio de más. Olvidaste transcribir ese error que te marca.

      Eliminar
    4. si, las rutas están bien, de hecho cambio el numero de la imagen manualmente y si cambia (la que pongo por defecto)
      lo hago en sublime text y no me marca ningún error ni en el navegador. El problema es que no se utilizar CodepenxD , vere si puedo hacer algo rapido

      Eliminar
    5. parece que ya encontre mi errorxD
      en la linea tenia esto, la doble comilla de la extension del archivo la tenia mal puesta,no me habia dado cuenta hasta que lo copie en Codepen:
      document.querySelector("figure#cambiado").style.backgroundImage =
      "url(/trabajos/Files_PHP/PHP/SubirFicheros/images/" + Math.floor (Math.random() * 14) + ".jpg");

      e iba asi:
      document.querySelector("figure#cambiado").style.backgroundImage =
      "url(/trabajos/Files_PHP/PHP/SubirFicheros/images/" + Math.floor (Math.random() * 14) + ".jpg)";

      Eliminar
    6. otra dudaxD, cuando voy cargando la pagina porq en algunas ocasiones llega a estar el fondo completamente blanco (sin imagen) ? si en random pongo el numero total de imagenes que tengo

      Eliminar
    7. Bien. La "consola" de Codepen te marcó el error. Para el caso es tan buena como la del navegador.
      Si te queda un fondo sin imagen, podés darle click con el botón secundario del maus y abrir "Inspeccionar elemento". Ahí ves si la ruta de imagen está bien en el src y de última la copias y la ves en la barra de direcciones; si no abre, es porque el archivo está corrupto.

      Eliminar
    8. otra dudaxD, cuando voy cargando la pagina porq en algunas ocasiones llega a estar el fondo completamente blanco (sin imagen) ? si en random pongo el numero total de imagenes que tengo

      Eliminar
    9. he subido la pagina a google drive
      https://583d7af5ec0f3e126a6b04a729290b4049d7b7b7.googledrive.com/host/0B8BCv1s3v29pbjRMc0dYTmhJSlU/

      el error que me da es el 404 failed to load resource, a que puede deberse esto? me pasa ahi donde la subi y también en elservidor local

      Eliminar
    10. Si no sabés por qué te da un 404 en tu sitio, estamos en problemas.

      La imagen 0.jpg no está.

      Suerte con tu página.Mclaren.

      Eliminar
    11. la imagen obviamente si esta en el directorio , mi pregunta es porque no la carga?

      Eliminar
    12. Hola Mclaren
      El enlace al G Drive que facilitaste no es público (pide usuario y contraseña para acceder a él, al menos a mi).

      Así mismo, dado que el código js funciona por fín y el problema sólo se manifiesta con una sola imagen quiere decir que el quebranto no procede de lo expuesto en este artículo si no del material nuevo usado por ti.

      Por lo tanto nada podemos hacer para encontrar tu error, excepto indicarte que hagas unas comprobaciones básicas y generalistas.

      Lo que deberás hacer es verificar que:
      ⊕ La imagen existe
      ⊕ Su nombre sea igual al resto de imágenes y que sólo cambia el numeral.
      ⊕ Que la extensión del archivo se corresponde con el tipo real de imagen.
      ⊕ El archivo no está corrupto.
      ⊕ Que por su tamaño o alguna otra razón demore tanto su carga que no se muestre.
      ⊕ ... étc

      Un saludo

      Eliminar
  2. Hola Kseso y furoya. Después de algún tiempo vuelvo a escribirles (bastante tiempo ya). Lo cierto es que hace mucho hice una consulta en este artículo
    https://escss.blogspot.com/2014/11/menu-letras-deslizantes-por-opcion.html
    , el tema era poder hacer que aparecieran diferentes imágenes en el menú cada vez que se entraba al blog. Por supuesto su respuesta fue rápida lo cual agradezco, e incluso furoya explica en este artículo la forma de hacerlo. Ahora bien, debo aclarar que me dedico a la fotografía y no a la programación, vale esta aclaración ya que lo poco que he logrado para armar el blog lo he hecho a fuerza de voluntad y consultas a gente como ustedes que tienen bien claro cada uno de estos temas, y por lo cual agradezco enormemente,
    Cuando publicaron este articulo pensé en ponerme manos a la obra para ver si lo podía lograr, pero . . . . . . definitivamente lo mío es la fotografía y no la programación.
    Siempre me quedé con el menú original ya que para mí era más que suficiente, hasta que claro también quedó la idea de que algún día tal vez lo podría conseguir.
    Hoy con más tiempo he vuelto a intentarlo y gracias a furoya he avanzado un poco, solo un poco.
    Si me permiten vamos al grano. Después de leer el artículo he logrado hacer esto:
    https://dl.dropboxusercontent.com/u/129278703/ALEATORIO/index.html
    y realmente es lo que quería lograr, las imágenes van cambiando cada vez que actualizo el enlace.
    Ahora bien y perdonen la pregunta, ya que por eso aclaro el no tener idea de programación.
    ¿Cómo hago para incluir esto?
    https://dl.dropboxusercontent.com/u/129278703/ALEATORIO/index.html
    en esto
    https://escss.blogspot.com/2014/11/menu-letras-deslizantes-por-opcion.html
    Me refiero a que en el primer enlace puedo ver el código fuente html donde se encuentra el CSS y javascript necesarios:

    Cómo hago para incluirlo dentro de esto?


    section {
    background: url(http://farm4.staticflickr.com/3812/11008866284_314123e642.jpg) no-repeat top center fixed;
    background-size: cover;
    height: calc(100vh - 3rem);
    transition: .4s linear 2s;
    }


    que es parte del CSS original del menú y así de esta forma poder conservar lo.

    Tal vez estoy pidiendo demasiado para mi conocimiento, pero bueno al menos puedo intentarlo con la ayuda de los mejores.
    Desde ya, muchas gracias por su tiempo.
    Un cordial saludo.

    ResponderEliminar
    Respuestas
    1. Hola Fabián Jofre.

      Adhiero al comentario que alguna vez hizo Kseso : muy buenas fotos.

      Leí tu consulta, y no sé si entiendo bien el problema. Si querés integrar a tu rotador de fondos el menú animado, no hay más que agregarlo. Tus fondos están en un 'figure' que ocupa todo el viewport en posición absoluta. El html que le agregues a la página debe ir a continuación, para que en la vista final quede "adelante" y no tapado "detrás" del 'figure'.

      El CSS también iría en el 'head', debajo del 'style' que ya tenés con el link. Por prolijidad, te conviene crear una nueva etiqueta 'style' para los formatos del menú allí en el 'head', que no sería otra cosa que copiar y pegar el código que ofrece Kseso, igual que su HTML; están los dos en el pen.

      Y ya arranca todo. Después ajustás el formato para que no te pase como a mí, que pensé que no funcionaba porque las letras son oscuras y el fondo que me tocó también, y entonces no las veía :P .

      No sé qué otro problema puede haber. Lo probé en Firefox y anduvo bien.

      Un saludo.

      Eliminar

EsCss RSS del Blog RSSS Comentarios Humans.txt ᛯ Diseno por Kseso SiteMap