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>
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.
By modifying the coordinate space, CSS transforms change the shape and position of the affected content without disrupting the normal document flow.
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.
The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.
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>
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With