JSFiddle - React, Tailwind, and code Playground
by rhumaric
HTML
<script src="http://fonts.googleapis.com/css?family=Peralta"></script>
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Peralta">
<h1>What was under the tree?</h1>
<ul class="gifts">
<li class="gift">A yummy gift</li><!--
--><li class="gift">A funny gift</li><!--
--><li class="gift">A noisy gift</li>
</ul>
<div class="buttons">
<button name="add-gift">Even more!</button>
</div>
<script type="application/x-template">
@keyframes {{animationId}} {
0% {
height: 0;
margin-bottom: 0;
-webkit-transform: translateX(-200%);
transform: translateX(-200%);
}
60% {
height: {{height}}px;
margin-bottom: 1em;
-webkit-transform: translateX(-200%);
transform: translateX(-200%);
}
100% {
height: {{height}}px;
margin-bottom: 1em;
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@-webkit-keyframes {{animationId}} {
0% {
height: 0;
margin-bottom: 0;
-webkit-transform: translateX(-200%);
transform: translateX(-200%);
}
60% {
height: {{height}}px;
margin-bottom: 1em;
-webkit-transform: translateX(-200%);
transform: translateX(-200%);
}
100% {
height: {{height}}px;
margin-bottom: 1em;
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
</script>
CSS
@import url('https://fonts.googleapis.com/css?family=Peralta');
* {
box-sizing: border-box;
}
body {
font-family: 'Peralta', cursive;
line-height: 2;
color: hsl(45,95%,75%);
background: hsl(150, 90%, 30%);
margin: 0;
padding-top: 1em;
text-align: center;
}
h1 {
text-align: center;
font-weight: normal;
margin: 0;
line-height: 1.5;
}
.clone {
position: absolute;
top: 0;
left: 0;
visibility: hidden;
}
.gifts {
text-align: left;
padding: 0 1em;
}
.gift {
list-style-type: none;
margin-bottom: 1em;
background: rgba(255,255,255, .2);
padding-left: 1em;
}
.gift::before {
content: '';
display: inline-block;
width: 2em;
text-align: center;
position: relative;
top: .25em;
left: -.5em;
color: hsl(202, 80%, 30%);
background-image: url("...
JavaScript
var gifts = document.querySelector('.gifts');
var firstElement = document.querySelector('.gift:nth-child(1)');
var button = document.querySelector('button');
button.addEventListener('click', function (event) {
var gift = createGift('A gift so big<br>one line was<br>not enough');
console.log('New element measurements (px): ', gift.offsetWidth, 'x', gift.offsetHeight);
var size = measureInsertedElement(gifts, gift);
var styleTag = createAnimation(size.height);
gift.style['animation'] = styleTag.getAttribute('data-animationName') + ' 0.75s';
gift.style['-webkit-animation'] = styleTag.getAttribute('data-animationName') + ' 0.75s';
// Cleanup the `style` property so that the `animation`
// CSS property can be set using a class, ID or element
// selector in a stylesheet
gift.addEventListener('animationend', function cleanup(event) {
this.style.animation = '';
});
gift.addEventListener('webkitAnimationEnd', function cleanupWebkit(event) {
this.style['-webkit-animation'];
});
gifts.insertBefore(gift, firstElement.nextSibling);
});
function createGift(label) {
var gift = document.createElement('li');
gift.innerHTML = label;
gift.classList.add('gift');
return gift;
}
function cloneContainer(container) {
var clone = container.cloneNode();
clone.classList.add('clone');
clone.style.width = container.clientWidth;
clone.style.height = container.clientHeight;
return clone;
}
function measureInsertedElement(container, element) {
// We don't want to insert the element in the
// actual container, so we'll clone it
var containerClone = cloneContainer(container);
// If the clone is not in the document,
// the measured size will still be 0x0 :(
document.body.appendChild(containerClone);
// Depending on how you insert the element,
// the insertion might need a bit more logic.
//...