Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a CSS transform affect the flow of other elements

I'm using CSS transitions with the transform property to shrinks elements when adding and removing them.

However one problem with this is that this property doesn't affect the flow of other elements, so it appears as though the element being deleted shrinks away, and then the rest of the elements jump suddenly.

If I were to animate the height property instead of using a transform this would be fine, however in actual usage I am using elements of variable height so I won't know what heights I can animate between.


Edit: people have suggested animating the height property (which won't work as stated above), or the max-height property. The max-height property will work to some extent, however you cannot align the timings perfectly as the transition will keep adjusting the max-height property past the actual height of the element until the end of the transition time.

Another problem with these approaches is that it does not use the smooth animations that you can achieve with the transform property. The object's transform will happen smoothly, however the movement of the following elements will stutter as the browser renders these transitions differently.


Here's a JSFiddle with what I mean (try adding then removing elements, and see the jump when elements are removed):

var button = document.querySelector("button");
var box = document.createElement("div");

box.className = "box";
box.appendChild(document.createTextNode("Click to delete"));

button.addEventListener("click", function(e) {
  var new_box = box.cloneNode(true);

  new_box.addEventListener("click", function(e) {
    this.className = "box deleting";
    window.setTimeout(function(e) {
      new_box.remove();
    }, 1000);
  });

  this.parentNode.appendChild(new_box);
});
button {
  font-size: 20pt;
}
.box {
  font-size: 20pt;
  margin: 10px;
  width: 200px;
  padding: 10px;
  background: pink;
  transform: scale(1, 1);
  transform-origin: top left;
}
.deleting {
  transform: scale(1, 0);
  transition: all 1000ms ease;
}
<button>
  Add Box
</button>
like image 670
Lauren Avatar asked Aug 27 '16 18:08

Lauren


People also ask

Does transform interfere with other elements or layout of a webpage?

For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element.

Does a transform disrupt the normal flow of a document?

By modifying the coordinate space, CSS transforms change the shape and position of the affected content without disrupting the normal document flow.

How do you trigger transform in CSS?

To trigger an element's transition, toggle a class name on that element that triggers it. To pause an element's transition, use getComputedStyle and getPropertyValue at the point in the transition you want to pause it. Then set those CSS properties of that element equal to those values you just got.

What does the transform CSS property allow you to do?

The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.


2 Answers

For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element.

REF: Transform Rendering

You will have to use the max-height property (check this answer) to get the desired effect.

var button = document.querySelector("button");
var box = document.createElement("div");

box.className = "box";
box.appendChild(document.createTextNode("Click to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to delete"));

button.addEventListener("click", function(e) {
  var new_box = box.cloneNode(true);
  new_box.style.height = ( Math.random() * (200 - 30) + 30 ) + 'px';

  new_box.addEventListener("click", function(e) {
    this.className = "box deleting";
    window.setTimeout(function(e) {
      new_box.remove();
    }, 1000);
  });

  this.parentNode.appendChild(new_box);
});
button {
  font-size: 20pt;
}
.box {
  overflow:hidden;
  font-size: 12pt;
  margin-bottom: 10px;
  width: 600px;
  max-height:1000px;
  padding: 10px;
  background: pink;
  transform: scaleY(1);
  transform-origin: top left;
}
.deleting {
  transform: scaleY(0);
  max-height:0;
  padding:0 10px;
  margin-bottom:0;
  transition: padding 1000ms ease,max-height 1000ms ease, transform 500ms ease 500ms, margin-bottom 1000ms ease;
}
<button>
  Add Box
</button>
like image 157
sabithpocker Avatar answered Sep 30 '22 15:09

sabithpocker


There's no way to do it right (with css alone) ¬¬

The way I did it was partially using JS (or C#/Blazor in my case)

I used the max-height but I set it with a var(), and the value itself I'm calculating based on the content that I have (I'm using JS/c# for that), then use that value to set an inline style withe the css variable:

<ul 
    class="submenu @SubMenuActiveClass" 
    style="--max-height:@((int)(40.3f * Model.Children.Count))px">

    <!--... childrens with 40.3px height each -->

</ul>
.submenu {
    max-height: 0;
    transition: max-height 0.3s ease-out;
    overflow: hidden;

    &.active {
        max-height: var(--max-height);
    }
}

The example is in Blazor and SCSS but it's quite easy to understand

like image 28
Ivan Schuaste Cavalheiro Avatar answered Sep 30 '22 14:09

Ivan Schuaste Cavalheiro