0

I've been implementing some CSS animations as named classes so I can easily add/remove any associated animation for an element, making it "available" for subsequent or repeat animations.

I'm dipping my toes into using CSS variables and it's currently throwing me for a loop. I'm trying to allow the user to rotate an active image in 90 degree increments. In the code example below, I'm showing only the positive 90 button click event.

*.scss

:root {
  --rotation-degrees: 90;
}

@keyframes rotate {
  100% {
    transform: rotate(var(--rotation-degrees)+'deg');
  }
}

.animation-rotate {
  --rotation-degrees: 90;
  // NOTE: I suspect the variable does not need to be supplied here, removing does 
  // not fix the issue, at least in isolation
  animation: rotate(var(--rotation-degrees)) 0.2s forwards;
}

*.js

let degrees = 0;
function rotate(degrees_increment) {
  degrees += degrees_increment;

  // The use of document.documentElement.style.setProperty is something I've seen 
  // used in many of the articles I've read as a means to "get to" the css variable, 
  // so I'm simply blindly copying it's use here   
  document.documentElement.style.setProperty('--rotation-degrees', degrees +'deg');
  $('#main-image-slider img').addClass('animation-rotate');
}

$('#rotate-right-button').on('click', function(event) {
  event.preventDefault();
  rotate(90);
});

Thank you in advance for any insights and help you can give!

3 Answers 3

1

I don't think it's possible to concatenate a CSS variable with a string as you were trying in your CSS:

 transform: rotate(var(--rotation-degrees)+'deg');

It's better to handle that with JavaScript.

I think the main issue you're having is that the class needs to be removed after the animation has run (in order for it to be able to run again). You can do that with the animationend event listener.

Demo below:

const DIV = $('div');
const BUTTON = $('#rotate-right-button');
const SPAN = $('#variable-value');
const PROPERTY_NAME = '--rotation-degrees';
const DEG = 'deg';
const ROOT = document.documentElement;
const ElementClass = {
  ROTATE_ANIMATION: 'animation-rotate'
}
const ROTATION_VALUE = 90;
const Event = {
  CLICK: 'click',
  ANIMATION_END: 'animationend'
}

let degrees = 0;

function rotate(degrees_increment) {
  degrees += degrees_increment;
  ROOT.style.setProperty(PROPERTY_NAME, degrees + DEG);
  
  SPAN.html(`${PROPERTY_NAME}: ${degrees + DEG}`);
}

BUTTON.on(Event.CLICK, function() {
  DIV.addClass(ElementClass.ROTATE_ANIMATION);
  DIV.on(Event.ANIMATION_END, function(event) {
    $(this).removeClass(ElementClass.ROTATE_ANIMATION);
  });
  
  rotate(ROTATION_VALUE);
});
@keyframes rotate {
  100% {
    transform: rotate(var(--rotation-degrees));
  }
}

.animation-rotate {
  animation: rotate 0.2s;
}

div {
  background: red;
  width: 100px;
  height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button id="rotate-right-button">rotate</button>
<br>
<span id="variable-value"></span>

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @sol for the time you put into your answer! You picked up on the main issue I'm having and that animationend event listener is precisely what I was after!
1

I think the highlighted code is not triggering the animation again when adding a class - Existing Code

var angle = 0;

$("#rotate").click(function(e){
	angle+= 90;
  document.documentElement.style.setProperty('--deg', angle+'deg');
  var el = $(".square");
  var newone = el.clone(true);           
 	el.before(newone);        
 $(".square:last").remove();
});
:root {
  --deg: 180deg;
}

@keyframes rotate {
 100% {transform: rotate(var(--deg));}
} 
.animation-rotate {
  animation: rotate 0.9s forwards;
}

.square {
  background: hsl(300, 90%, 52%);
  width: 15vmin;
  height: 15vmin;
  border-radius: 10%;
  margin: 25px;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <div class="square animation-rotate"></div>
  <div>
    <button class="btn btn-sm btn-success" id="rotate">Rotate</button>
  </div>
</div>

1 Comment

Thank you for your comment @Ajit! Your thought of cloning the element is very interesting and something I had not considered before!
0

I'm not sure I understand your code, but here's my take on it.
When the user clicks, you can either:
- add/remove a CSS class. In that case the values for the rotation are already set in your CSS.
- rotate the element directly in JavaScript, for instance by dynamically setting a CSS rule.

Seems to me like you're doing both at the same time?

1 Comment

Hi @mrtnmgs! Thanks for your comment. You're right, I'm trying to do a bit of both at the same time. In order to have the animation be able to fire more than once, I'm using a CSS class to trigger the animation rather than keeping it purely within JS. In order to make the rotation value dynamic depending on how many times the user clicks the button, I'm modifying the CSS angle through JS. Which admittedly, may not be a good way to go about it...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.