Animate shrink and expand transitions for subsets of elements in a nested set of divs in javascript

I need to animate the shrink and expand transitions for subsets of elements in a nested set of divs. The expand works fine, but the shrink is broken.

I have a structured collection of items (say, squares for purposes here) that I want to display selectively and whose transitions I want to animate.

The structure is: collection > groups > rows > squares

In static layout,

  • squares appear in horizontal rows;
  • rows are gathered vertically in groups;
  • a column of groups forms the collection.

Squares can be of varying sizes, so containers must adjust accordingly (no fixed heights or widths).

I have obtained a static layout that is just what I want.

The problem comes with animation. I want to hide various subsets of squares, rows and/or groups. Nearby items can look similar so it is difficult for users to tell just what is being added or subtracted, so I need a smooth animation so users can follow what is changing.

I am trying to do this with a CSS-animated shrink:

  • A shrinkMe class marks all element that I will want to shrink/expand at the moment
  • CSS transition times are set for these shrinkMe elements
  • A shrunken class is defined whose CSS has all its size parameters set to 0
  • To shrink or expand, jQuery adds or removes the the shrunken class tag to the $('shrinkMe') items, to animate items between the full and shrunken (=0) sizes

The un-shrink animated transition is exactly what I want. But the shrink animation does not work at all - contents spill out of containers along the way.

shrink = function(bool,nsec) {
  $('.shrinkMe').css("transition", 'all ' + nsec+ 's');
  if (bool) $('.shrinkMe').addClass('shrunk')
  else $('.shrinkMe').removeClass('shrunk');
}
anim = function(secs) {
  return 'all ' + secs + 's'
}
.controls {
  display: inline-block;
  vertical-align: top;
}

.collection {
  display: inline;
  text-align: center;
  border: 2px solid black;
  padding: 3px;
  display: inline-block;
}

.group {
  display: block;
  margin: 2px;
  border: 2px solid black;
  padding: 3px;
}

.row {
  display: block;
  vertical-align: middle;
  background: #0cc;
  margin: 1px;
  border: 2px solid black;
}

.sq {
  display: inline-block;
  background: white;
  width: 20px;
  height: 20px;
  margin: 5px;
  border: 2px solid black;
}

.lg {
  width: 25px;
  height: 25px;
}

.shrinkMe {
  border-color: red;
}

.shrunk {
  height: 0px;
  width: 0px;
  border-width: 0px;
  padding: 0px;
  margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<div class='controls'>
  <button type='button' onclick='shrink(true,2)'>shrink reds </button>
  <br>
  <button type='button' onclick='shrink(false,2)'>unshrink reds </button>
</div>
<div class='collection'>
  <div class='group'>
    <div class='row '>
      <div class='sq'></div>
      <div class='sq'></div>
    </div>
    <div class='row shrinkMe'>
      <div class='sq lg shrinkMe'></div>
      <div class='sq shrinkMe'></div>
      <div class='sq lg shrinkMe'></div>
    </div>
  </div>
  <div class='group shrinkMe' id='group2'>
    <div class='row shrinkMe' id='group2container2'>
      <div class='sq shrinkMe'></div>
      <div class='sq shrinkMe'></div>
    </div>
    <div class='row shrinkMe'>
      <div class='sq shrinkMe'></div>
      <div class='sq lg shrinkMe'></div>
      <div class='sq shrinkMe'></div>
    </div>
  </div>
</div>

Among other things, I've tried using different explicit transition speeds, so containers shrink more slowly than their contents, but to no avail. If I set explicit heights and widths of the rows and groups, I can get a coordinated nested-shrink but it is ugly:

  1. It shrinks by squashing to the left side and;
  2. The final layouts can have empty spaces in them (e.g., when a row shrinks inside an unshrunk group, the fixed explicit group container height means there is now a hole where the row was).

What I want is to achieve is simple: a shrink animation that is the time-reverse of the nice clean un-shrink.

Here also is a jsfiddle showing the problem that additionally has buttons for trying separate timings of more deeply nested divs (which does not help...)

https://jsfiddle.net/furnas/dgq8yusy/

Any explanation of what is going wrong and suggestions on how to fix it?

1 answer

  • answered 2017-06-17 18:53 lasha maraneli

    Use jquery anymation onComplete event for adding and removing classes to divs.

    because your css transition works like asyncronous method on another thread, so, you need to wait for it to complete and than add/remove classes.

    http://api.jquery.com/animate/