0

Trying to build an hamburger button with animation using css transitions/transforms. I would like the rotation to start only after the translation of the first and the third span is completed (they should overlap with the middle span). Thus I put the transforms chained in the css like so:

transform: translate(0, -28px) rotate(-45deg);

but it seems not working, rotation starts together with translation. Anyone knows how to fix?

$( window ).load(function() {
  
  $("#hamburger").click(function(){
    $(this).toggleClass("open");
  });
  
});
*, *:before, *:after {
  box-sizing: border-box;
}

body {
  background-color: #333;
}

#hamburger {
  margin: 2em;
  position: relative;
  width: 80px;
  height: 60px;
  cursor: pointer;
}

#hamburger span {
  display: block;
  position: absolute;
  left: 0;
  width: 100%;
  height: 4px;
  background: #fff;
  
  -webkit-transition: transform .25s linear;
  -moz-transition: transform .25s linear;
  -o-transition: transform .25s linear;
  transition: transform .25s linear;
  
  &:nth-child(2) {
    -webkit-transition: width 0s linear .25s;
    -moz-transition: width 0s linear .25s;
    -o-transition: width 0s linear .25s;
    transition: width 0s linear .25s;
  }
}

#hamburger span:nth-child(1) {
  top: 0;
}

#hamburger span:nth-child(2) {
  top: 28px;
}

#hamburger span:nth-child(3) {
  bottom: 0;
}

#hamburger.open span:nth-child(1) {
  -webkit-transform: translate(0, 28px) rotate(45deg);
  -moz-transform: translate(0, 28px) rotate(45deg);
  -o-transform: translate(0, 28px) rotate(45deg);
  transform: translate(0, 28px) rotate(45deg);
}

#hamburger.open span:nth-child(2) {
  width: 0;
}

#hamburger.open span:nth-child(3) {
  -webkit-transform: translate(0, -28px) rotate(-45deg);
  -moz-transform: translate(0, -28px) rotate(-45deg);
  -o-transform: translate(0, -28px) rotate(-45deg);
  transform: translate(0, -28px) rotate(-45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="hamburger">
    <span></span>
    <span></span>
    <span></span>
</div>

3
  • 1
    This isn't "chaining" in any temporal sense, it is just specifying two different transformation functions at the same time - but this is still one singular value assigned to the transform property, and you can not transition this singular value as two separate things. If you want this to work without having to use a JS delay, then use a CSS animation instead of a transition. Inside the keyframes you will be able to specify what each of the two transformation functions should be doing at any point separately. Commented Nov 4, 2017 at 21:40
  • Thanks! I've just realized that that's the order of the matrix multiplication but not the temporal order of the animations, as you pointed out. I've tried using css keyframe animations as you suggested and it worked on the first animation, but it is not clear how to reverse the keyframe animation when you remove the css class. Commented Nov 5, 2017 at 1:35
  • I think you might have to use a second class to apply the explicitly defined reverse animation. If you were to specify the reverse animation for the default element "state", without any class, it would play on page load already, which is probably not what you want. Your button would actually have three states then - how it has to behave when the menu "is closed" differs, based on whether the menu is closed because we are initially loading the page, or because we clicked to close the menu that was already opened. Commented Nov 5, 2017 at 1:47

2 Answers 2

4

You could split your transform into two different classes, one with translate() and one with rotate(), and then split up the transitions with .delay(), like so:

$("#hamburger").click(function(){
    $(this).toggleClass("translateClass");
    $(this).delay(250).toggleClass("rotateClass");
);
Sign up to request clarification or add additional context in comments.

Comments

0

Solved following @Kadin Zhang suggestion splitting the animation in two transitions. I've substituted the translate transform with a simple change in the top property because in this way the transform-origin moves with the element (otherwise the origin remains in the previous coordinate system and the rotation will be wrong).

$( window ).load(function() {
  
  var state = false;
  
  $("#hamburger").click(function(){
    self = $(this);
    if (!state) {
      self.addClass("open-translate");
      setTimeout(function() {
        self.addClass("open-rotate");
        state = true;
      }, 250);
    }
    else {
      self.removeClass("open-rotate");
      setTimeout(function() {
        self.removeClass("open-translate");
        state = false;
      }, 250);
    }    
  });
  
});
*, *:before, *:after {
  box-sizing: border-box;
}

body {
  background-color: #333;
}

#hamburger {
  margin: 2em;
  position: relative;
  width: 80px;
  height: 60px;
  cursor: pointer;
}

#hamburger span {
  display: block;
  position: absolute;
  left: 0;
  width: 100%;
  height: 4px;
  background: #fff;
  
  -webkit-transition: all .25s linear;
  -moz-transition: all .25s linear;
  -o-transition: all .25s linear;
  transition: all .25s linear;
  
  &:nth-child(2) {
    -webkit-transition: width 0s linear .25s;
    -moz-transition: width 0s linear .25s;
    -o-transition: width 0s linear .25s;
    transition: width 0s linear .25s;
  }
}

#hamburger span:nth-child(1) {
  top: 0;
}

#hamburger span:nth-child(2) {
  top: 28px;
}

#hamburger span:nth-child(3) {
  top: 56px;
}

#hamburger.open-translate span:nth-child(1) {
  top: 28px;
}


#hamburger.open-rotate span:nth-child(1) {
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
}

#hamburger.open-translate span:nth-child(2) {
  width: 0;
}

#hamburger.open-translate span:nth-child(3) {
  top: 28px;
}

#hamburger.open-rotate span:nth-child(3) {
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  transform: rotate(-45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="hamburger">
    <span></span>
    <span></span>
    <span></span>
</div>

Comments

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.