30

I am try to have the caret in the following rotate 180 degrees on click for my dropdown menu. In the solution Im trying to implement, it changes the class of the the caret to toggle-up or toggle-down on click. The first time I click on it rotates up, the second time it immediately goes back to its starting position and then rotates back up. I smell dirty code, whats the easiest way to add this toggle rotation animation. Thanks in advance for any help.
Heres my current css:

.toggle-up {
  animation-name: toggle-up;
  animation-delay: 0.25s;
  animation-duration: 0.75s;
  animation-fill-mode: forwards;
}
.toggle-down {
  animation-name: toggle-down;
  animation-delay: 0.25s;
  animation-duration: 0.75s;
  animation-fill-mode: forwards;
}

/*animations*/
@keyframes toggle-up {
  100% {
    transform: rotate(180deg);
  }
}
@keyframes toggle-down {
  100% {
    transform: rotate(180deg);
  }
}

enter image description here

Daniel Kobe
  • 9,376
  • 15
  • 62
  • 109
  • do you mean that the state after your first rotate up is not preserved and when you click on it again, it again performs the rotate up? If yes I think you should use javascript to preserve the state of the last animation – Megha Jun 29 '15 at 06:15

3 Answers3

64

You don't really need a keyframe animation for something this simple. If you just add a class to your icon on click then remove it this will apply your rotation. Here is a working plunkr using font awesome and a simple rotation. This is just a simple example, you will want to make use of vendor prefixes and be aware that css transitions do not work in older browsers.

<div id="container">
    <i id="icon" class="fa fa-arrow-down"></i>
</div>

.fa-arrow-down{
  transform: rotate(0deg);
  transition: transform 1s linear;
}

.fa-arrow-down.open{
  transform: rotate(180deg);
  transition: transform 1s linear;
}

(function(document){
  var div = document.getElementById('container');
  var icon = document.getElementById('icon');
  var open = false;

  div.addEventListener('click', function(){
    if(open){
      icon.className = 'fa fa-arrow-down';  
    } else{
      icon.className = 'fa fa-arrow-down open';
    }

    open = !open;
  });
})(document);
Kevin F
  • 2,836
  • 2
  • 16
  • 21
24
.square {
  width: 100px;
  height: 100px;
  background-color: #ff0000;
  transition: all 0.75s 0.25s;
}

.toggle-up {
  transform: rotate(180deg);
}

.toggle-down {
  transform: rotate(0);
}

You should have an initial state in order to complete your animation.

Here is the example: codepen

UPDATE

Here is the version without using javascript: codepen

<label for="checkbox">
  <input type="checkbox" id="checkbox">
  <div class="square toggle-down"></div>
</label>


#checkbox {
  display: none;
}

.square {
  width: 100px;
  height: 100px;
  background-color: #ff0000;
  transition: all 0.75s 0.25s;
  transform: rotate(0);
}

#checkbox:checked + .square {
  transform: rotate(180deg);
}

The general idea is to change the block class using Adjacent sibling selectors and the checkbox checked state.

arm.localhost
  • 479
  • 4
  • 9
  • I see, thanks, I was trying to figure out how to use the transition instead. Whats the purpose of the tilda operator in the javascript if statement in your codepen? – Daniel Kobe Jun 29 '15 at 06:21
  • Oh, sorry. I am trying to write this without using JS. It is the draft. I will bring it to the intial state. – arm.localhost Jun 29 '15 at 06:23
3

An easy way to implement with bootstrap

.caret {
    transition: 0.5s;
}
  .caret:not(.collapsed){
    transform: rotate(180deg);
  }
  .caret:is(.collapsed) {
    transform: rotate(0deg);
  }
    
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js"></script>


<div class="d-flex">
  <span class="bi bi-chevron-down caret collapsed" role="button" data-bs-toggle="collapse" data-bs-target="#detail"></span>
  <div id="detail" class="collapse">
    Hi!
  </div>
</div>