2

Lets say I've got a box that I want to wobble when hovered over - a nuance design choice. But when a button is clicked I want the box to transform to the right. It does this, but even though I'm applying pointer-events: none to the element, its still reacting to its CSS hover effect telling it to wobble, which interrupts the CSS transform activated by the button click. I'm not sure why pointer-events: none isn't doing the job,

To observe this problem, hover over the box after clicking the button, while it's in motion.

How do I keep the wobble animation from interrupting while the transform transition is in progress?

$(function() {
  var $box = $('.box');
  var $button = $('.button');
  
  $button.on('click', function() {
    $box.css({
      'transform' : 'translateX(200px)',
      'pointer-events' : 'none !important'
    });
    setTimeout(function(){
     $box.css({
       'transform' : 'translateX(0px)',
        'pointer-events' : ''
     });
    }, 3000);
  });
});
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,800);

.box {
  background-color: lightgray;
  width: 100px;
  height: 100px;
  transition: transform 3s, background-color 1s;
}

.box:hover {
  background-color: gold;
  animation: wobble 1s;
}

.button {
  cursor:pointer;
  font-family: 'Open Sans', sans-serif;
  margin-top:10px;
  text-transform: uppercase;
  padding:10px;
  background-color:lightgreen;
  width:100px;
  height:40px;
  box-sizing:border-box;
  text-align:center;
}

@keyframes wobble {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(3deg);
  }
  75% {
    transform: rotate(-3deg);
  }
  100% {
    transform: rotate(0deg);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box"></div>
<div class="button">button</div>

3 Answers3

1

You might attached the wobble to a class and toggle the class as you need. I'm not sure you are looking for it, but this solution allows the box to return slide to the left smoothly. It also allows for the color on hove effect to remain working.

$(function() {

  var $box = $('.box');
  var $button = $('.button');
  
  $button.on('click', function() {
    $box.removeClass("wobble");
    $box.addClass("slide");
    setTimeout(function() {
      $box.removeClass("slide");
      setTimeout(function(){ $box.addClass("wobble"); }, 3000);
    }, 3000);
  });

});
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,800);

.box {
  background-color: lightgray;
  width: 100px;
  height: 100px;
  transform : translateX(0px);
  transition: transform 3s, background-color 1s;
}

.box:hover { background-color: gold; }
.box.wobble:hover { animation: wobble 1s; }
.box.slide { transform : translateX(200px); }

.button {
  cursor:pointer;
  font-family: 'Open Sans', sans-serif;
  margin-top:10px;
  text-transform: uppercase;
  padding:10px;
  background-color:lightgreen;
  width:100px;
  height:40px;
  box-sizing:border-box;
  text-align:center;
}

@keyframes wobble {
    0% { transform: rotate(0deg); }
   25% { transform: rotate(3deg); }
   75% { transform: rotate(-3deg); }
  100% { transform: rotate(0deg); }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box wobble"></div>
<div class="button">button</div>
JonSG
  • 10,542
  • 2
  • 25
  • 36
0

The simplest solution you could try would be to add a class to your js event and add the :not(class) selector on hover.

You could also make the animation transform out of the class to keep it on the css, if you don't need the transform action to be necessarily calculated by the javascript. This keeps code cleaner.

$(function() {
  var $box = $('.box');
  var $button = $('.button');
  
  $button.on('click', function() {
    $box.css({
      'transform' : 'translateX(200px)',
      'pointer-events' : 'none !important'
    });
    $box.addClass("animation");
    setTimeout(function(){
     $box.css({
       'transform' : 'translateX(0px)',
        'pointer-events' : ''
     });
      $box.removeClass("animation");
    }, 3000);
  });
});
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,800);

.box {
  background-color: lightgray;
  width: 100px;
  height: 100px;
  transition: transform 3s, background-color 1s;
}

.box:not(.animation):hover {
  background-color: gold;
  animation: wobble 1s;
}

.button {
  cursor:pointer;
  font-family: 'Open Sans', sans-serif;
  margin-top:10px;
  text-transform: uppercase;
  padding:10px;
  background-color:lightgreen;
  width:100px;
  height:40px;
  box-sizing:border-box;
  text-align:center;
}

@keyframes wobble {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(3deg);
  }
  75% {
    transform: rotate(-3deg);
  }
  100% {
    transform: rotate(0deg);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box"></div>
<div class="button">button</div>
Forty
  • 305
  • 3
  • 15
  • Could you show me what you mean on the code snippet with "copy snippet to answer"? I created that simplified example of my problem so that answers could easily demonstrate a solution with the code. Because I'm having some trouble understanding exactly what you mean. –  Jul 01 '16 at 02:02
  • I've added a snippet. The downside is that you cannot add multiple selectors inside :not, so this will not work if you have a more complex case in which you'd need multiple. – Forty Jul 01 '16 at 02:07
  • I'm not sure the box does the "return slide" correctly – JonSG Jul 01 '16 at 02:16
  • True, the timeout is set halfway, he'd need a separate timeout at 6000 to be the proper transition finish time. Not exactly a very neat solution. – Forty Jul 01 '16 at 02:26
0

You can toggle animationPlayState of element style to "paused" during transition, to "running" following transition within setTimeout call; use .one(), transitionend event to reset animationPlayState to "running". See also Pausing CSS animation with javascript and also jumping to a specific place in the animation

$(function() {
  var $box = $('.box')
  var $button = $('.button');
  
  $button.on('click', function() {
    $box.css({
      'transform' : 'translateX(200px)',
      'pointer-events' : 'none !important'
    })
    // set `$box` `animationPlayState` to `"paused"`
    [0].style.animationPlayState = "paused";
    setTimeout(function(){
     $box
        .one("transitionend", function(e) {
           // set `$box` `animationPlayState` to `"running"`
          this.style.animationPlayState = "running";
        })  
        .css({
       'transform' : 'translateX(0px)',
        'pointer-events' : ''
     })             
    }, 3000);
  });
});
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,800);

.box {
  background-color: lightgray;
  width: 100px;
  height: 100px;
  transition: transform 3s, background-color 1s;
}

.box:hover {
  background-color: gold;
  animation: wobble 1s forwards;
}

.button {
  cursor:pointer;
  font-family: 'Open Sans', sans-serif;
  margin-top:10px;
  text-transform: uppercase;
  padding:10px;
  background-color:lightgreen;
  width:100px;
  height:40px;
  box-sizing:border-box;
  text-align:center;
}

@keyframes wobble {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(3deg);
  }
  75% {
    transform: rotate(-3deg);
  }
  100% {
    transform: rotate(0deg);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box"></div>
<div class="button">button</div>
Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
  • 1
    On chrome if you keep your mouse over the box on the return slide it gets all jumpy. – JonSG Jul 01 '16 at 02:15
  • @JonSG See updated post, adjusted to using `.one()`, `transitionend` event – guest271314 Jul 01 '16 at 02:31
  • It is better, but on the return slide, try letting the slide start then mouse over the box and rapidly jiggle the mouse. On my chrome browser it sometimes work perfectly, sometimes just teleports home, and sometimes has a kind of stuttering fit. :-) – JonSG Jul 01 '16 at 02:38
  • Your answer seem conceptually superior to mine. Pausing and resuming the animation seems at a high level a better solution to toggling a class. It is just not working (for me) quite as I would have hoped. – JonSG Jul 01 '16 at 02:44
  • @JonSG The `transitionend` event is not fired at the same point in time for same `transition`; also there are several `transition` events occurring at `js`, `css`. Added `forward` as `animation-timing-function`, which may have effected rendering. Actually, `setTimeout` could possibly be removed – guest271314 Jul 01 '16 at 02:59