Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Labels don't activate associated fields when part of an animation

Playing with web technologies, I developed a dice using just HTML and CSS (without JavaScript). It's a simple system: a series of radio buttons and labels that simulate the dice by changing their positioning (with z-index) so every time that you click on the dice, there's a "random" number.

This is a minimal version of the code:

@keyframes changeOrder {
  from { z-index: 6;}
  to { z-index: 1; }
}

@-webkit-keyframes changeOrder {
  from { z-index: 6; }
  to { z-index: 1; }
}

label {
  display: block;
  position: absolute;
  display: block;
  width: 50px;
  height: 50px;
  line-height:50px;
  background: #eeeeee;
  text-align: center;
  animation: changeOrder 1.2s infinite;
}

label:nth-of-type(1) { animation-delay: 0s; }
label:nth-of-type(2) { animation-delay: -0.2s; }
label:nth-of-type(3) { animation-delay: -0.4s; }
label:nth-of-type(4) { animation-delay: -0.6s; }
label:nth-of-type(5) { animation-delay: -0.8s; }
label:nth-of-type(6) { animation-delay: -1.0s; }
<input type="radio" name="cb" id="cb1" value="1"/>
<input type="radio" name="cb" id="cb2" value="2"/>
<input type="radio" name="cb" id="cb3" value="3"/>
<input type="radio" name="cb" id="cb4" value="4"/>
<input type="radio" name="cb" id="cb5" value="5"/>
<input type="radio" name="cb" id="cb6" value="6"/>
<label for="cb1">1</label>
<label for="cb2">2</label>
<label for="cb3">3</label>
<label for="cb4">4</label>
<label for="cb5">5</label>
<label for="cb6">6</label>

The problem happens when, even when the dice is rolling, it not always takes action when the label is clicked on, and the radio button associated to the label is not activated. Sometimes it does, sometimes it doesn't.

I thought it could be because of the animation I used, and (unsuccessfully) played with the times to see if that would fix the problem... but it basically remains the same. I noticed that if I extend the times, the issue "disappears" (i.e. changing the times to 3s and delays in 0.5s or higher). But if I do that, it is more predictable (the goal is not to make it perfect but at least simulate some pseudo-randomness).

Why could this be happening? What can I do to fix it?

like image 206
Alvaro Montoro Avatar asked Jul 20 '18 20:07

Alvaro Montoro


1 Answers

As you already noticed it, the issue is due to how fast the animation is. The changes is faster than the click because a click is two actions: mousedown and mouseup and both should be done on the same element.

Here is a better illustration of the issue where you can NEVER make the input checked by clicking on the labels:

label {
  display: block;
  position: absolute;
  display: block;
  width: 50px;
  height: 50px;
  line-height:50px;
  background: #eeeeee;
  text-align: center;
}

label:active {
  background:red;
  z-index:-1;
}
<input type="radio" name="cb" id="cb1" value="1">
<input type="radio" name="cb" id="cb2" value="2">
<label for="cb1">1</label>
<label for="cb2">2</label>

When clicking, the element will be hidden and the mouseup will no more be on the same element thus the click event is not done. The same is happening with your example is some cases.


An Idea to fix this is to allow the click to end by making the clicked element on the top until the end of the click event.

Here is an idea where I rely on a pseudo element with a big z-index so I can keep the click event on the needed element. You can also make the animation faster!

.container {
 position:relative;
}
label {
  display:block;
  position: absolute;
  top:0;
  left:0;
  width: 50px;
  height: 50px;
  line-height:50px;
  background: #eeeeee;
  text-align: center;
  animation: changeOrder 0.6s infinite;
}
@keyframes changeOrder {
  from { z-index: 6;}
  to { z-index: 1; }
}
label:nth-of-type(1) { animation-delay: 0s; }
label:nth-of-type(2) { animation-delay: -0.1s; }
label:nth-of-type(3) { animation-delay: -0.2s; }
label:nth-of-type(4) { animation-delay: -0.3s; }
label:nth-of-type(5) { animation-delay: -0.4s; }
label:nth-of-type(6) { animation-delay: -0.5s; }

label:active {
  /*Mandatory to break the stacking context and allow 
   the pseudo element to be above everything*/
  position:static; 
  /*For illustration*/
  margin-left: 50px;
  background:red;
}

label:active::before {
  content:"";
  position:absolute;
  top:0;
  right:0;
  left:0;
  bottom:0;
  z-index:10;
}
<input type="radio" name="cb" id="cb1" value="1">
<input type="radio" name="cb" id="cb2" value="2">
<input type="radio" name="cb" id="cb3" value="3">
<input type="radio" name="cb" id="cb4" value="4">
<input type="radio" name="cb" id="cb5" value="5">
<input type="radio" name="cb" id="cb6" value="6">
<div class="container"> 
 <label for="cb1">1</label>
 <label for="cb2">2</label>
 <label for="cb3">3</label>
 <label for="cb4">4</label>
 <label for="cb5">5</label>
 <label for="cb6">6</label>
</div>
like image 97
Temani Afif Avatar answered Nov 18 '22 12:11

Temani Afif