Existem números aleatórios em CSS?



O CSS permite criar layouts e interfaces dinâmicos na Internet, mas como linguagem de marcação é estática - você não pode alterá-lo após definir o valor. A idéia do acaso não é discutida. A geração de números aleatórios em tempo de execução é um território de JavaScript, não de CSS.

Ou não? Se permitirmos um pouco de interação do usuário, podemos realmente gerar algum grau de aleatoriedade no CSS. Vamos dar uma olhada!

Aleatoriedade em outros idiomas


Existem maneiras de obter alguma "randomização dinâmica" usando variáveis ​​CSS, como Robin Rendle explica em um artigo sobre truques CSS . Mas essas soluções não são 100% CSS, pois requerem JavaScript para atualizar a variável CSS com um novo valor aleatório.

Podemos usar pré-processadores como Sass ou Less para gerar valores aleatórios, mas assim que o código CSS é compilado e exportado, os valores são fixos e a aleatoriedade é perdida.

Por que estou preocupado com valores aleatórios em CSS?


No passado, desenvolvi aplicativos simples apenas de CSS, como Quiz , jogo de CS Simon e Magic Trick , mas eu queria fazer algo mais complexo.

* Deixarei uma discussão sobre a validade, utilidade ou praticidade da criação desses trechos em CSS somente posteriormente.

Com base no fato de que alguns jogos de tabuleiro podem ser representados como máquinas de estado (FSMs), eles podem ser representados usando HTML e CSS.

Portanto, comecei a desenvolver o jogo "Leela" (também é "Snakes and Ladders").

Este é um jogo simples. Em resumo, o objetivo do jogo é avançar o chip do começo ao fim do tabuleiro, evitando cobras e tentando subir as escadas.

O projeto parecia viável, mas eu perdi alguma coisa, sim, com certeza - dados!
Jogar dados (em outros jogos, jogar moedas) são métodos geralmente aceitos para obter valores aleatórios. Você joga dados ou lança uma moeda e cada vez que obtém um valor desconhecido. Tudo parece simples.

Simulação de um lançamento aleatório de ossos


Eu ia sobrepor as camadas com rótulos e usar animação CSS para "girar" e compartilhar qual camada estava no topo. Algo assim:



O código para simular essa randomização não é muito complicado e pode ser alcançado usando a animação e vários atrasos na animação:

/*   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; } 

A animação foi mais lenta para simplificar a interação (mas ainda rápida o suficiente para ver o obstáculo explicado abaixo). A pseudo-aleatoriedade também é mais 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"; } 

Mas então me deparei com uma certa limitação. Eu obtive números aleatórios, mas às vezes, mesmo quando clicava em "dados", o campo não retornava nenhum valor.

Tentei aumentar o tempo de animação e isso pareceu ajudar um pouco, mas ainda havia valores inesperados.

Foi então que fiz o que a maioria dos desenvolvedores faz quando encontra obstáculos que não conseguem resolver - procurei ajuda no StackOverflow. Eu recomendo.

Felizmente para mim, sempre haverá pessoas dispostas a ajudar, no meu caso, foi Temani Afif com sua explicação .

Se você tentar simplificar, o problema é que o navegador aciona o evento click apenas quando o elemento está no estado ativo (quando o mouse é clicado), ou seja, é o mesmo elemento ativo quando o botão do mouse é pressionado.

Devido à alteração da animação, a camada superior (etiqueta), quando você clicou no mouse, na verdade, não era a camada superior (etiqueta) quando o mouse foi pressionado, a menos que eu tenha feito rápido o suficiente, bem ou lentamente, para que a animação já esteja conseguiu passar por todos os valores do ciclo. É por isso que o aumento no tempo de animação ocultou esse problema.

A solução foi aplicar a posição “estática” para quebrar o contexto da pilha e usar um pseudo-elemento como :: before ou :: after com um índice z mais alto para substituí-lo. Assim, o rótulo ativo estará sempre no topo quando você passa o 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; } 

Aqui está o código com uma solução com menor tempo de animação:


Depois de fazer essa alteração, resta criar uma pequena interface para desenhar pseudo cubos que podem ser clicados com o mouse, e o jogo CSS Snakes and Ladders foi concluído.

Essa técnica tem algumas desvantagens óbvias.


  1. É necessária interação com o usuário - é necessário clicar em um rótulo para causar "geração de números aleatórios".
  2. O método não escala bem - funciona muito bem com pequenos conjuntos de valores, mas é um problema para grandes intervalos.
  3. Este não é um aleatório real, mas ainda uma pseudo-aleatoriedade, e o computador pode determinar facilmente qual valor será gerado a cada momento.

Mas, por outro lado, é 100% CSS (não há necessidade de pré-processadores ou outros auxiliares externos) e, para uma pessoa, pode parecer 100% aleatório.

E, sim, esse método pode ser usado não apenas para números aleatórios, mas também para tudo aleatório. Nesse caso, usamos para "acidentalmente" selecionar um computador no jogo "Pedra-papel-tesoura".

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


All Articles