Daniel Marques
Daniel Marques

Reputation: 526

Animating HTML element position on DOM change

I have a list of tags that form a tag cloud. I'll include a search option that will hide/remove the tags that don't match the search. If I do this the tag cloud will rearrange automatically, but it will be instantaneously. I want some form of animation.

I've researched and discovered that the attribute position is not animatable. I've played around with MutationObserver and was able to detect changes in the DOM but was still unsure of what to do on the callback function.

.tagcloud ul {
	margin: 0;
	padding: 0;
	list-style: none;
}
.tagcloud ul li {
	position: relative;
	display: inline-block;
	margin: 0 .75em .5em 0;
	padding: 0;
}
.tagcloud ul li a {
	position: relative;
	display: inline-block;
	height: 28px;
	line-height: 28px;
	padding: 0 1em;
	background: #fff;
	border: 1px solid #aaa;
	border-radius: 3px;
	word-wrap: normal;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow: hidden;
	color: #333;
	font-size: 13px;
	text-decoration: none;
	-webkit-transition: .2s;
	transition: .2s;
}
.tagcloud ul li span {
	position: absolute;
	top: 0;
	right: -10px;
	z-index: 2;
	width: 28px;
	height: 28px;
	line-height: 28px;
	background-color: #3498db;
	border: 1px solid #3498db;
	border-radius: 100%;
	color: #fff;
	font-size: 13px;
	text-align: center;
	opacity: 0;
	-webkit-transition: .2s;
	transition: .2s;
	-webkit-transform: scale(.4);
	transform: scale(.4);
}
.tagcloud ul li span::after {
	position: absolute;
	top: 50%;
	left: -8px;
	content: '';
	width: 0;
	height: 0;
	margin-top: -7px;
	border-color: transparent #3498db transparent transparent;
	border-style: solid;
	border-width: 7px 14px 7px 0;
}
.tagcloud ul li a:hover {
	border: 1px solid #3498db;
	color: #3498db;
}
.tagcloud ul li:hover span {
	right: -26px;
	opacity: 1;
	-webkit-transform: scale(1);
	transform: scale(1);
}
<div class="tagcloud">
      	<ul>
      		<li><a href="#">javascript</a><span>10</span></li>
      		<li><a href="#">android</a><span>6</span></li>
      		<li><a href="#">c++</a><span>20</span></li>
      		<li><a href="#">c</a><span>15</span></li>
      		<li><a href="#">java</a><span>16</span></li>
      		<li><a href="#">html</a><span>4</span></li>
      		<li><a href="#">css</a><span>11</span></li>
      		<li><a href="#">python</a><span>17</span></li>
      		<li><a href="#">artificial intelligence</a><span>5</span></li>
      		<li><a href="#">computer graphics</a><span>9</span></li>
      		<li><a href="#">php</a><span>8</span></li>
      		<li><a href="#">computer audio</a><span>7</span></li>
      		<li><a href="#">database</a><span>7</span></li>
      		<li><a href="#">web</a><span>12</span></li>
      		<li><a href="#">sql</a><span>6</span></li>
      	</ul>
      </div>

Upvotes: 0

Views: 462

Answers (1)

User 28
User 28

Reputation: 5158

This might not answer your question directly because in my opinion hiding element is a lot easier than remove it (or wait it removed).

After input event triggered, for each element we need to determine to do some animations or ignore it. In case of do animation we need to determine more between 2 animations which are exit animation (animate element then hide it) and entry animtion (show element then animate it).

input.addEventListener('input', event => {
  let re = new RegExp(input.value)

  ul.querySelectorAll('li').forEach(li => {
    let isHidden = li.style.display === 'none'
    let shouldHide = !re.test(li.textContent)

    if (shouldHide && !isHidden) {
      // Play exit animation
    }

    if (!shouldHide && isHidden) {
      // Play entry animation
    }
  })
})

I suggest to use javascript animation library (in example I use animejs) to handle animation instead of pure css animation because we need to toggle display which not working on pure css.

See full example here.

I hope this help. Thanks.

Upvotes: 1

Related Questions