3

Hello I want to transition div's height smoothly when I append an element to it, but I cannot get it to work I read this SO post smooth growing of div when appending children using transitions

but it does not answer the question correctly as it is fading in the element opposed to transitioning the div's height that the elements are in

http://jsfiddle.net/nexq40oz/

setInterval(function() {
    var li = document.createElement("li");
    li.innerHTML = "item";
    document.getElementById("list").appendChild(li);
}, 1000);
#menu #list {
    max-height: 300px;
    transition: max-height 0.15s ease-out;
    background: #d5d5d5;
}
<div id="menu">
    <ul id="list">
        <!-- Create a bunch, or not a bunch, of li's to see the timing. -->
        <li>item</li>
        <li>item</li>
    </ul>
</div>
Alex Mortez
  • 156
  • 1
  • 8

2 Answers2

1

const ul = document.getElementById('list');
const item = document.querySelector('#list > li');

setInterval(function() {
  let h = ul.offsetHeight;
  let h_item = item.offsetHeight;

  var li = document.createElement("li");
  li.innerHTML = "item";
  document.getElementById("list").appendChild(li);

  ul.style.maxHeight = 'calc(' + h + 'px + ' + h_item + 'px)';
}, 1000);
#menu #list {
  overflow: hidden;
  max-height: 20px;
  transition: max-height 0.15s ease-out;
  background: #d5d5d5;
}

#list>li {
  height: 20px;
}
<div id="menu">
  <a>hover me</a>
  <ul id="list">
    <!-- Create a bunch, or not a bunch, of li's to see the timing. -->
    <li>item</li>
  </ul>
</div>
Andrei Fedorov
  • 3,689
  • 2
  • 13
  • 25
1

You need to add a class that transition the max-height of the li element and add with requestAnimationFrame to have an effect on the parent element,

setInterval(function() {
    var li = document.createElement("li");
    li.innerHTML = "item";
    document.getElementById("list").appendChild(li);
    requestAnimationFrame(() => requestAnimationFrame(() => li.classList.add('expand')))

}, 1000);
#menu #list {
    background: #d5d5d5;
}

#menu #list li {
  max-height: 0;
  transition: max-height 1s ease-out;
}

#menu #list li.expand {
  max-height: 200px;
}
<div id="menu">
    <ul id="list">
        <!-- Create a bunch, or not a bunch, of li's to see the timing. -->
        <li>item</li>
        <li>item</li>
    </ul>
</div>
Mina
  • 14,386
  • 3
  • 13
  • 26
  • This doesn't seem to have the effect I want, this answer is similar to the other SO answer I linked in my original post. I don't want to animate the items, but rather height of the container that holds the items. Run Andrei Fedorov's code snippet to see what I mean. – Alex Mortez Oct 28 '22 at 14:15
  • I am on firefox, and it seems to work around 25% of the time. I added `setTimeout(() => {requestAnimationFrame(() => li.classList.add('expand'))}, 20)` and it seems to work more often. – Alex Mortez Oct 28 '22 at 14:27
  • @AlexMortez, Run inside two `requestAnimateFrame` callbacks and it will work 100%, this will guarantee to add the class after painting. – Mina Oct 28 '22 at 14:31
  • Running two works 100% of the time, can confirm. thanks for this! – Alex Mortez Oct 28 '22 at 14:39
  • 1
    @AlexMortez If you are confused why use two `requestAnimateFrame` I suggest you [watch this video](https://www.youtube.com/watch?v=cCOL7MC4Pl0), especially at `20:30` – Mina Oct 28 '22 at 14:45