¿Hay números aleatorios en CSS?



CSS le permite crear diseños dinámicos e interfaces en Internet, pero como lenguaje de marcado es estático, no puede cambiarlo después de establecer el valor. La idea del azar no se discute. La generación de números aleatorios en tiempo de ejecución es un territorio de JavaScript, no CSS.

O no? Si permitimos una pequeña interacción del usuario, podemos generar cierto grado de aleatoriedad en CSS. ¡Echemos un vistazo!

Aleatoriedad en otros idiomas


Hay formas de obtener algo de "aleatorización dinámica" utilizando variables CSS, como Robin Rendle explica en un artículo sobre trucos CSS . Pero estas soluciones no son 100% CSS, ya que requieren JavaScript para actualizar la variable CSS con un nuevo valor aleatorio.

Podemos usar preprocesadores como Sass o Less para generar valores aleatorios, pero tan pronto como se compila y exporta el código CSS, los valores son fijos y se pierde la aleatoriedad.

¿Por qué me preocupan los valores aleatorios en CSS?


En el pasado, desarrollé aplicaciones simples de CSS como Quiz , el juego de CS Simon y Magic Trick , pero quería hacer algo más complejo.

* Dejaré una discusión sobre la validez, utilidad o practicidad de crear estos fragmentos en CSS solo en un momento posterior.

Basado en el hecho de que algunos juegos de mesa pueden representarse como máquinas de estado (FSM), entonces pueden representarse usando HTML y CSS.

Por lo tanto, comencé a desarrollar el juego "Leela" (también es "Serpientes y escaleras").

Este es un juego simple. En resumen, el objetivo del juego es avanzar la ficha desde el principio hasta el final del tablero, evitando serpientes e intentando subir las escaleras.

El proyecto parecía factible, pero me perdí algo, sí, claro, ¡dados!
Lanzar dados (en otros juegos, lanzar monedas) son métodos generalmente aceptados para obtener valores aleatorios. Lanzas dados o lanzas una moneda, y cada vez que obtienes un valor desconocido. Todo parece simple.

Simulación de un lanzamiento aleatorio de huesos.


Iba a superponer las capas con etiquetas y usar animación CSS para "rotar" y compartir qué capa estaba encima. Algo como esto:



El código para simular esta aleatorización no es demasiado complicado y se puede lograr usando animación y varios retrasos de animación:

/*   z-index -     */ @keyframes changeOrder { from { z-index: 6; } to { z-index: 1; } } /*        */ label { animation: changeOrder 3s infinite linear; background: #ddd; cursor: pointer; display: block; left: 1rem; padding: 1rem; position: absolute; top: 1rem; user-select: none; } /*  ,        */ label:nth-of-type(1) { animation-delay: -0.0s; } label:nth-of-type(2) { animation-delay: -0.5s; } label:nth-of-type(3) { animation-delay: -1.0s; } label:nth-of-type(4) { animation-delay: -1.5s; } label:nth-of-type(5) { animation-delay: -2.0s; } label:nth-of-type(6) { animation-delay: -2.5s; } 

La animación se ralentizó para simplificar la interacción (pero aún lo suficientemente rápido como para ver el obstáculo explicado a continuación). La seudoaleatoriedad también es más clara.


 <label for="d1">Click here to roll the dice</label> <label for="d2">Click here to roll the dice</label> <label for="d3">Click here to roll the dice</label> <label for="d4">Click here to roll the dice</label> <label for="d5">Click here to roll the dice</label> <label for="d6">Click here to roll the dice</label> <div> <input type="radio" id="d1" name="dice"> <input type="radio" id="d2" name="dice"> <input type="radio" id="d3" name="dice"> <input type="radio" id="d4" name="dice"> <input type="radio" id="d5" name="dice"> <input type="radio" id="d6" name="dice"> <p>You got a: <span id="random-value"></span></p> </div> 

 @keyframes changeOrder { from { z-index: 6;} to { z-index: 1; } } label { animation: changeOrder 3s infinite linear; background: #ddd; cursor: pointer; display: block; left: 1rem; padding: 1rem; position: absolute; top: 1rem; user-select: none; } label:nth-of-type(1) { animation-delay: 0s; } label:nth-of-type(2) { animation-delay: -0.5s; } label:nth-of-type(3) { animation-delay: -1.0s; } label:nth-of-type(4) { animation-delay: -1.5s; } label:nth-of-type(5) { animation-delay: -2.0s; } label:nth-of-type(6) { animation-delay: -2.5s; } div { left: 1rem; position: absolute; top: 5rem; width: 100%; } #d1:checked ~ p span::before { content: "1"; } #d2:checked ~ p span::before { content: "2"; } #d3:checked ~ p span::before { content: "3"; } #d4:checked ~ p span::before { content: "4"; } #d5:checked ~ p span::before { content: "5"; } #d6:checked ~ p span::before { content: "6"; } 

Pero luego me encontré con una cierta limitación. Obtuve números aleatorios, pero a veces, incluso cuando hice clic en "dados", el campo no devolvió ningún valor.

Traté de aumentar el tiempo de animación, y pareció ayudar un poco, pero aún tenía algunos valores inesperados.

Fue entonces cuando hice lo que la mayoría de los desarrolladores hacen cuando encuentran obstáculos que no pueden resolver: pedí ayuda en StackOverflow. Lo recomiendo

Afortunadamente para mí, siempre habrá personas dispuestas a ayudar, en mi caso fue Temani Afif con su explicación .

Si trató de simplificar, el problema fue que el navegador dispara un evento de clic solo cuando el elemento está en el estado activo (cuando se hace clic con el mouse), en otras palabras, es el mismo elemento que está activo cuando se presiona el botón del mouse.

Debido al cambio de animación, la capa superior (etiqueta) cuando se presionó el mouse, de hecho, no era esa capa superior (etiqueta) cuando se presionó el mouse, a menos que lo hiciera lo suficientemente rápido, bien o lentamente, de modo que la animación ya logró pasar por todos los valores del ciclo. Es por eso que el aumento en el tiempo de animación ha ocultado este problema.

La solución fue aplicar la posición "estática" para romper el contexto de la pila y usar un pseudo-elemento como :: before o :: after con un índice z más alto para tomar su lugar. Por lo tanto, la etiqueta activa siempre estará en la parte superior cuando pase el mouse.

 /*   label      */ label:active { margin-left: 200%; position: static; } /*         z-index */ label:active::before { content: ""; position: absolute; top: 0; right: 0; left: 0; bottom: 0; z-index: 10; } 

Aquí está el código con una solución con un tiempo de animación más rápido:


Después de hacer este cambio, queda por crear una pequeña interfaz para dibujar pseudo cubos en los que se puede hacer clic con el mouse, y el juego CSS Snakes and Ladders se ha completado.

Esta técnica tiene algunas desventajas obvias.


  1. Se requiere la interacción con el usuario: es necesario hacer clic en una etiqueta para provocar la "generación de números aleatorios".
  2. El método no se escala bien: funciona muy bien con pequeños conjuntos de valores, pero es una molestia para grandes rangos.
  3. Esto no es un azar real, pero sigue siendo una seudoaleatoriedad, y la computadora puede determinar fácilmente qué valor se generará en cada momento.

Pero, por otro lado, es 100% CSS (no hay necesidad de preprocesadores u otros ayudantes externos), y para una persona puede parecer 100% aleatorio.

Y sí, este método puede usarse no solo para números aleatorios, sino también para todo al azar. En este caso, lo usamos para seleccionar "accidentalmente" una computadora en el juego "Piedra-papel-tijera".

Source: https://habr.com/ru/post/474818/


All Articles