You can't apply a pure css transition to the sizing change on the parent which occurs when an element is added/deleted from the form.
Here's one solution using transitioned margin-bottom to decrease the space the element takes up in the parent, and scale(1, 0)
to make the element visually decrease in size.
setInterval(function() {
let form = document.getElementsByTagName('form')[0];
let formItem = form.children[Math.floor(Math.random() * 3)];
formItem.classList.toggle('hidden');
}, 1000);
.page {
position: fixed;
box-sizing: border-box;
width: 100%; height: 100%;
left: 0; top: 0;
padding: 30px;
}
form {
position: relative;
background-color: #a0a0a0;
}
.form-item {
height: 50px;
margin-bottom: 0;
overflow: hidden;
position: relative;
outline: 1px solid black;
background-color: #a0a0a0;
transform-origin: 0% 0%;
transform: scale(1, 1);
transition: margin-bottom 1s ease-in-out, transform 1s ease-in-out;
}
.form-item.hidden {
margin-bottom: -50px;
transform: scale(1, 0);
}
.form-item > .label {
margin: 0;
color: #ffffff;
}
<div class="page">
<form>
<div class="form-item">
<p class="label">Item 1</p>
<input type="text" name="item1"/>
</div>
<div class="form-item">
<p class="label">Item 2</p>
<input type="text" name="item2"/>
</div>
<div class="form-item">
<p class="label">Item 3</p>
<input type="text" name="item3"/>
</div>
<div class="form-item">
<p class="label">Item 4</p>
<input type="text" name="item4"/>
</div>
<div>
<input type="button" name="prev" value="Prev"/>
<input type="button" name="next" value="Next"/>
</div>
</form>
</div>
A limitation here is that you need to know the height of the input field ahead of time. You'll note that it's hardcoded to 50px
in this example.
Note: Don't worry about "too many transitions". The browser will certainly be able to manage a bunch of height-transitioning child elements.