naveen
naveen

Reputation: 433

Css animation: transition not working in reverse direction

I am trying to make this side navbar using HTML/CSS in which I am adding some hover animations. whenever you hover on an icon it will scale to double and the rest of the items in the navbar disperse. But my problem is not that because I already achieved that animation using javascript and CSS. The problem is the animation is not working smoothly in the reverse direction. so I was trying to add short CSS animation to check whether reverse animation transition working properly or not and it is not.

here's my CSS code:

ul{
    list-style: none;
    }
    .navmenu{
      position: fixed;
      top: 50%;
      transform: translateY(-50%);
    }
    .navmenu ul{
      padding-left: 40px;
      position: relative;
    }
    .navmenu ul li {
      padding: 15px 0;
    }
    .navmenu ul li a{
      text-decoration: none;
      position: relative;
      font-size: 1.8rem;
      font-weight: 900;
    }
    .navmenu ul li a i{
      -webkit-transition: all 2s ease-in;
              transition: all 2s ease-in;
    }
    .navmenu ul li a:hover i{
      -webkit-animation: slide-out-top 0.2s ease-out both;
              animation: slide-out-top 0.2s ease-out both;
      color: orange;
    }

    @-webkit-keyframes slide-out-top {
      0% {
        -webkit-transform: scale(1) translateY(0);
                transform: scale(1) translateY(0);
      }
      100% {
        -webkit-transform: scale(0.8,0.8) translateY(-60px);
                transform: scale(0.8,0.8) translateY(-60px);
      }
    }
    @keyframes slide-out-top {
      0% {
        -webkit-transform: scale(1) translateY(0);
                transform: scale(1) translateY(0);
      }
      100% {
        -webkit-transform: scale(0.8,0.8) translateY(-60px);
                transform: scale(0.8,0.8) translateY(-60px);
      }
    }

here's its HTML code:

<nav class="navmenu">
    <ul>
      <li><a href="#home" class=""><i class="fas fa-home"></i><span>Home</span></a></li>
      <li><a href="#projects" class=""><i class="fas fa-laptop-code"></i><span>Projects</span></a></li>
      <li><a href="#skills" class=""><i class="fas fa-code"></i><span>Skills</span></a></li>
      <li><a href="#training" class=""><i class="fas fa-dumbbell"></i><span>Training</span></a></li>
      <li><a href="#education" class=""><i class="fas fa-user-graduate"></i><span>Education</span></a> 
      </li>
      <li><a href="#contact_me" class=""><i class="far fa-address-book"></i><span>Contact me</span></a> 
      </li>
    </ul>
</nav>

https://codepen.io/naveen444/pen/zYooJzd?editors=1100

I have read on the internet that animations and transitions are different and transitions can be reversed but not animations but I have used CSS animations before and I remember transitions: all 2s; can reverse all the transitions smoothly. Pardon me if I have said anything wrong. I am an absolute beginner in this and please correct me.

Upvotes: 1

Views: 3135

Answers (4)

Nik
Nik

Reputation: 1709

You can do transform: scale(0.8) translateY(-60px); on hover instead of adding animation. I've changed following css and forked your codepen. This is working as you want.

.navmenu ul li a i{
  position: relative;
  -webkit-transition: -webkit-transform 1s;
  transition: transform 1s;
  color: orange;
}
.navmenu ul li a:hover i{
  -webkit-transform: scale(0.8) translateY(-60px);
  transform: scale(0.8) translateY(-60px);
  color: orange;
}

Here is the snippet as well.

body {
  background: black;
}

ul {
  list-style: none;
}

.navmenu {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
}

.navmenu ul {
  padding-left: 40px;
  position: relative;
}

.navmenu ul li {
  padding: 15px 0;
}

.navmenu ul li a {
  text-decoration: none;
  position: relative;
  font-size: 1.8rem;
  font-weight: 900;
}

.navmenu ul li a span {
  font-size: 1rem;
  padding-left: 20px;
  color: orange;
  /*   transition: all 0.1s; */
  font-weight: 600;
  display: none;
}

.navmenu ul li a i {
  position: relative;
  -webkit-transition: -webkit-transform 1s;
  transition: transform 1s;
  color: orange;
}

.navmenu ul li a:hover i {
  -webkit-transform: scale(0.8) translateY(-60px);
  transform: scale(0.8) translateY(-60px);
  color: orange;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />

<body>
  <nav class="navmenu">
    <ul>
      <li><a href="#home" class=""><i class="fas fa-home"></i><span>Home</span></a></li>
      <li><a href="#projects" class=""><i class="fas fa-laptop-code"></i><span>Projects</span></a></li>
      <li><a href="#skills" class=""><i class="fas fa-code"></i><span>Skills</span></a></li>
      <li><a href="#training" class=""><i class="fas fa-dumbbell"></i><span>Training</span></a></li>
      <li><a href="#education" class=""><i class="fas fa-user-graduate"></i><span>Education</span></a></li>
      <li><a href="#contact_me" class=""><i class="far fa-address-book"></i><span>Contact me</span></a></li>
    </ul>
  </nav>

</body>

Upvotes: 1

dale landry
dale landry

Reputation: 8610

You could define your before and after states with class styling and add/remove these classes with event listeners. One state, would have a mouseover listener, while the other would have a mouseleave listener. You would then need to define your before and after states using css. Then add your @keyframes rules to these specific classes.

For example, you have a class that styles an element, we could call this the before state #icon. Then you have a class that would be the hover state slidein. Style this to how you wish the state to look when the animation finishes its tween. Set up your animation parameters in the @keyframes rule for that specific class. Then you set up another class for the mouseout state, this has a specific style on how you want the element to look once it returns to its original state. Add the @keyframes rule according to the elements state from mouseover. Lastly, use a setTimeout to remove the mouseout states class that coincides with the animations timing duration.

I have added a yellow BG on elements parent to illustrate the relationship between hovering the triggering eventlistener and the animating element.

const icon = document.querySelectorAll('.icon')

const animate = (el, duration) => {
  const root = document.documentElement;
  // conditional that sets the CSS variable to the duration called in your function
  // using the css :root element, checks if the duration is over one second and 
  // formats the root variable to seconds/milliseconds accordingly
  if (`${duration}`.length > 3) {
    let whole = `${duration}`.slice(0, `${duration}`.length - 3);    
    root.style.setProperty('--duration', `${whole}s`);
  } else {
    root.style.setProperty('--duration', `.${duration}s`);
  }
  el.forEach((node) => {
    node.addEventListener('mouseenter', (e) => {
      node.children[0].classList.add('slidein');
    })
    node.addEventListener('mouseleave', (e) => {
      node.children[0].classList.add('slideout');
      node.children[0].classList.remove('slidein');
      setTimeout(() => {
        node.children[0].classList.remove('slideout')
      }, duration)
    })
  })
  console.log(root)
}

animate(icon, 650)
:root {
  --top-pos: -30px;
  --duration: 0.7s;
  --scale-to: scale(0.6)
}

#parent {
  margin-top: 30px;
  height: 50px;
  width: 50px;
}

.icon img {
  width: 50px;
  height: 50px;
}

.icon {
  margin: 10px 0;
  background: yellow;
}

.slidein {
  animation: slidein var(--duration) ease-out;
  position: relative;
  top: var(--top-pos);
  transform: var(--scale-to);
}

.slideout {
  animation: slideout var(--duration) ease-out;
  position: relative;
  transform: var(--scale-to);
  top: 0px;
}

@keyframes slidein {
  0% {
    top: 0px;
    transform: scale(1);
  }
  100% {
    top: var(--top-pos);
    transform: var(--scale-to);
  }
}

@keyframes slideout {
  0% {
    top: var(--top-pos);
    transform: var(--scale-to);
  }
  100% {
    top: 0px;
    transform: scale(1);
  }
}
<div id="parent">
  <div class="icon">
    <img src="https://nextgate.com/wp-content/uploads/2018/02/icon-implementation.png">
  </div>
  <div class="icon">
    <img src="https://res.cloudinary.com/logrhythm/image/upload/c_scale,w_175/v1519675460/icons/training-advanced-admin-icon.png">
  </div>
  <div class="icon">
    <img src="http://haltin.com.tr/wp-content/uploads/2015/12/icon_integrity-6.png">
  </div>
  <div class="icon">
    <img src="http://www.stephensre.com/images/icons-selling/icon-inspect.png">
  </div>
</div>

Upvotes: 0

Yudiz Solutions
Yudiz Solutions

Reputation: 4459

Can you please check the below code link? Hope it will work for you.

You can do smooth animation using transition property on navbar icon using transform and transition property and without using animation and @-webkit-keyframes.

Please refer to this link: https://jsfiddle.net/yudizsolutions/zpL3yc4n/

Upvotes: 0

Akshay K Nair
Akshay K Nair

Reputation: 1476

These aren't classic transitions, these are key frame animations. Going with pure CSS, you can do this;

.intern {
    -webkit-animation: in 1s;
}

.intern:hover {
    -webkit-animation: out 1s;
}

@-webkit-keyframes in {
    from   { -webkit-transform: rotate(0deg); }
    to { -webkit-transform: rotate(360deg);}
}

@-webkit-keyframes out {
    0%   { -webkit-transform: rotate(360deg); }
    100% { -webkit-transform: rotate(0deg); }
}
<div style = "width : 100px; height : 100px; background-color : red" class ="intern"></div>

Run the code snippet and you can find it executing out animation on mouse out.

Upvotes: 1

Related Questions