2

The other day I stumbled onto an example that uses Vue.js, but my question is more about the CSS and HTML that Vue uses to achieve the transition between states.

The cards temporarily get the class .shuffleMedium-move which adds a transition: transform 1s and the order of the nodes change in the DOM, but I don't understand why the transition occurs since the transform property never seems to get set and the items are positioned simply using float:left.

I've been doing CSS for quite a while and I've always had to resort to using a combination of JavaScript position: absolute and transform to achieve a similar result. Vue's solution seems really elegant, but I don't understand how it works.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
duprasa
  • 31
  • 5
  • 1
    The animation is done via classes, while you don't see these classes while inspecting because they are added/removed instantly. But if you put a `debugger` line in the shuffle function, after the vue(...) lines and inspect the dom, you will see the other classes. You have to inspect the card first then run the code, if you run the code and it starts debugging, you might not be able to inspect – Huangism Apr 17 '18 at 16:08
  • hmm I don't see any other classes added other than `shuffleMedium-move` which only adds `transition: transform 1s` I would expect to also see something like: `shuffleMedium-start` or `shuffleMedium-end` or adding inline styles, but vuejs doesn't seem to be doing any of that. – duprasa Apr 17 '18 at 17:36
  • The `transform` is really quickly added inline, then removed immediately. – Emile Bergeron Apr 17 '18 at 17:42
  • @duprasa those classes are added then removed you won't see them in inspector. I tested with transform time of 25s and when I set breakpoints in debugger I was able to see the classes – Huangism Apr 17 '18 at 20:19

1 Answers1

4

From the documentation on list transition

This might seem like magic, but under the hood, Vue is using an animation technique called FLIP to smoothly transition elements from their old position to their new position using transforms.

From the FLIP article

FLIP stands for First, Last, Invert, Play.

Let’s break it down:

  • First: the initial state of the element(s) involved in the transition.
  • Last: the final state of the element(s).
  • Invert: here’s the fun bit. You figure out from the first and last how the element has changed, so – say – its width, height, opacity. Next you apply transforms and opacity changes to reverse, or invert, them. If the element has moved 90px down between First and Last, you would apply a transform of -90px in Y. This makes the elements appear as though they’re still in the First position but, crucially, they’re not.
  • Play: switch on transitions for any of the properties you changed, and then remove the inversion changes. Because the element or elements are in their final position removing the transforms and opacities will ease them from their faux First position, out to the Last position.

Step by step example

That way, we can inspect changes at each step of the animation process.

When it's playing in real time, the transform is really quickly added inline and it's then removed immediately, so it looks like it's never set.

const el = document.getElementById('target');
const data = {};

function first() {
  data.first = el.getBoundingClientRect();
  console.log('First: get initial position', data.first.left, 'px');
}

function last() {
  el.classList.toggle('last');
  data.last = el.getBoundingClientRect();
  console.log('Last: get new position', data.last.left, 'px');
}

function invert() {
  el.style.transform = `translateX(${data.first.left - data.last.left}px)`;
  console.log('Invert: applies a transform to place the item where it was.');
}

function play() {
  requestAnimationFrame(() => {
    el.classList.add('animate');
    el.style.transform = '';
  });
  console.log('Play: adds the transition class and removes the transform.');
}

function end() {
  el.classList.remove('animate');
  console.log('End: removes the transition class.');
}

const steps = [first, last, invert, play, end];

let step = 0;

function nextStep() {
  steps[step++ % steps.length]();
}

document.getElementById('next').addEventListener('click', nextStep);
.last {
  margin-left: 35px;
}

.animate {
  transition: transform 1s;
}

#target {
  display: inline-block;
  padding: 5px;
  border: 1px solid #aaa;
  background-color: #6c6;
}

#next {
  margin-top: 5px;
}
<div id="target">target</div>
<br>
<button id="next" type="button">Next</button>
tony19
  • 125,647
  • 18
  • 229
  • 307
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • 1
    Thanks for the detailed answer :). I'll experiment with this a bunch, I'm still surprised chrome doesn't show the inline `transform` even though its almost instantaneous. – duprasa Apr 17 '18 at 19:10