Danny P
Danny P

Reputation: 83

How to smoothly transition between classes using jQuery

How do I make this the transition between classes smooth instead of the shaking effect that you see here: http://codepen.io/Cogarius/pen/tfhgx

The box shakes severely because of the differences in widths and heights along with changes to the border size which the classes are transitioning.

HTML:

<div class="outer">
  <div class="original"></div>
</div>

CSS:

.original {
  float: left;
  height: 0;
  width: 0;
  background: #ffffff;
  border: 150px solid #000000;
  margin: 0px;
}

.changed {
  float: left;
  height: 296px;
  width: 296px;
  border: 2px solid #ff3333;
  background: #ffffff;
  margin: 0px;
}

jQuery

$(document).ready(function(){
  $('.original').on('click', function(){  
    $(this).toggleClass( "changed", 500, "easeOutQuad" );
  });
});

Upvotes: 3

Views: 235

Answers (3)

Terry
Terry

Reputation: 66218

There are several ways you can approach this problem (and the good news is, they are all jitter free :D )

Box shadow

One trick is to use box shadows to your advantage. For the rest state, you ensure that the box shadow (inset) fills up the entire dimension of your box. For the toggled state, you collapse the box shadow by reducing its spread radius, and also by changing its colour. CodePen Demo

.original {
  height: 300px;
  width: 300px;
  background: #fff;
  box-shadow: inset 0 0 0 150px #000000;
  position: relative;
  transition: all .5s ease-in-out;
}
.changed {
  box-shadow: inset 0 0 0 2px #ff3333;
}

One caveat: You need to specify the spread radius (fourth number) in pixel values... so if you are using a responsive element, this might be an issue.

Another issue I can foresee is that since the spread radius has to be in pixel values, it might still show jittering as slow transition speeds. For a entirely jitter-free transition, I can only recommend taking advantage of CSS3 2D transforms, which we will need to use pseudo-elements (see next solution).


Pseudo-elements

This trick is to use a pseudo-element, e.g. ::before, on the container and then scale it when the classes are toggled. Under all states, the container has a black background with a 2px black border. The pseudo-element is absolutely positioned in the center and fills the width and height of its parents, but at rest state it is scaled to 0 (i.e. no size). At the toggled state we de-scale it back to its original dimensions. CodePen Demo

.original {
  box-sizing: border-box;
  height: 300px;
  width: 300px;
  background:#000;
  border: 2px solid #000;
  position: relative;
  transition: all .5s ease-in-out;
  &::before {
    background-color: #fff;
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    transition: all .5s ease-in-out;
    transform: scale(0);
  }
}

.changed {
  background-color: #ff3333;
  border-color: #ff3333;
  &::before {
    background-color: #fff;
    transform: scale(1);
  }
}

Note that I have used:

  • The box-sizing property, so the width declared is the final dimensions
  • Transitioning the border colour of the parent, as well as the background colour of the pseudo element.

Upvotes: 2

burakcalik
burakcalik

Reputation: 157

Changing the width and height values cause this situation. If you want a smooth transition, then you need to use a hardware accelerated css transform, like scale, translateX, translateY etc.

Here is a more descriptive article about that.

Upvotes: 0

James Donnelly
James Donnelly

Reputation: 128796

You can replace your current transition with CSS. Simply add a transition property to your .changed selector:

.changed {
    ...
    transition: 0.5s; /* Equal to 500ms */
}

The shakiness is still there, but it's less prominent than it was when handled through jQuery.

CodePen demo.

Upvotes: 1

Related Questions