Smooth shrinking animation

狂风中的少年 提交于 2020-01-08 06:21:04

问题


I would like to be able to shrink an HTML tag to make it disappear, and have a smooth disappearance for the remaining items (so that they don't jump where the tag used to be)

const div = document.querySelector('.toGo');

div.addEventListener('click', event => {
  div.className += ' animate';
  // Simulate Angular's DOM modification
  setTimeout(() => div.style.display = 'none', 1100);
  setTimeout(() => div.style.display = 'block', 1200);
  setTimeout(() => div.className = 'toGo', 1300);
});
.toGo, .toStay {
  height: 50px;
  width: 100%;
  background: coral;
  transition: all 1000ms ease-in-out;
  overflow: hidden;
}

.toStay {
  margin: 12px 0;
}

.animate {
  height: 0;
  width: 0;
  opacity: 0;
}
<div class="toGo">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tristique sed nisi id aliquet. Etiam mauris diam, commodo in nisl ac, porttitor auctor mi. Nunc et blandit lacus. Donec facilisis dolor in arcu convallis, eu molestie magna placerat. Etiam blandit diam vitae nibh sollicitudin, ac gravida risus convallis. Nunc aliquet, turpis ac dignissim mollis, nulla nisi cursus leo, quis viverra nisi augue eget leo. Curabitur porta faucibus vestibulum.
</div>
<div class="toStay">Lorem Ipsum</div>

<p>Click on the first div</p>

Right now, as you can see, the text is shifting because the space is shrinking.

At first, I tried with the transform property, but the second div was jumping at the place of the first one (because I am using Angular and the framework removes the first div from the DOM once the animation is complete).

const div = document.querySelector('.toGo');

div.addEventListener('click', event => {
  div.className += ' animate';
  // Simulate Angular's DOM modification
  setTimeout(() => div.style.display = 'none', 1100);
  setTimeout(() => div.style.display = 'block', 2100);
  setTimeout(() => div.className = 'toGo', 2200);
});
.toGo, .toStay {
  height: 50px;
  width: 100%;
  background: coral;
  transition: all 1000ms ease-in-out;
  overflow: hidden;
}

.toStay {
  margin: 12px 0;
}

.animate {
  transform: scale(0);
  opacity: 0;
}
<div class="toGo">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tristique sed nisi id aliquet. Etiam mauris diam, commodo in nisl ac, porttitor auctor mi. Nunc et blandit lacus. Donec facilisis dolor in arcu convallis, eu molestie magna placerat. Etiam blandit diam vitae nibh sollicitudin, ac gravida risus convallis. Nunc aliquet, turpis ac dignissim mollis, nulla nisi cursus leo, quis viverra nisi augue eget leo. Curabitur porta faucibus vestibulum.
</div>
<div class="toStay">Lorem Ipsum</div>

<p>Click on the first div</p>

I then tried this solution with the width/height, but the text is shifting. I then finally tried with a container in it, but it didn't change a thing (unless I set a fixed size to that inner container).

Is there a way to achieve that, without setting fixed width/height to the inner container ?

EDIT People are actually asking to close my question because it is "unclear". In case this wasn't obvious, I want the first snippet to stop shifting the text, and the second snippet to smoothly move the second div in place of the first one (without jumping).

Something like this, without the use of fixed sizes for the inner container

const div = document.querySelector('.toGo');

div.addEventListener('click', event => {
  div.className += ' animate';
  // Simulate Angular's DOM modification
  setTimeout(() => div.style.display = 'none', 1100);
  setTimeout(() => div.style.display = 'block', 1200);
  setTimeout(() => div.className = 'toGo', 1300);
});
.toGo, .toStay {
  height: 50px;
  width: 100%;
  background: coral;
  transition: all 1000ms ease-in-out;
  overflow: hidden;
}

.container {
  height: 50px;
  width: 100vw;
}

.toStay {
  margin: 12px 0;
}

.animate {
  height: 0;
  width: 0;
  opacity: 0;
}
<div class="toGo">
  <div class="container">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tristique sed nisi id aliquet. Etiam mauris diam, commodo in nisl ac, porttitor auctor mi. Nunc et blandit lacus. Donec facilisis dolor in arcu convallis, eu molestie magna placerat. Etiam blandit diam vitae nibh sollicitudin, ac gravida risus convallis. Nunc aliquet, turpis ac dignissim mollis, nulla nisi cursus leo, quis viverra nisi augue eget leo. Curabitur porta faucibus vestibulum.
  </div>
</div>
<div class="toStay">Lorem Ipsum</div>

<p>Click on the first div</p>

回答1:


Your main issue in the first snippet was related to margin collapsing creating the jump effect. Consider a flexbox container to avoid margin collapsing:

you can then consider a clip-path animation combined with height animation (don't animate the width to avoid the shrink effect)

const div = document.querySelector('.toGo');

div.addEventListener('click', event => {
  div.className += ' animate';
  
  // Simulate Angular's DOM modification
  setTimeout(() => div.style.display = 'none', 1100);
  setTimeout(() => div.style.display = 'block', 1200);
  setTimeout(() => div.className = 'toGo', 1300);
});
body {
  display:flex;
  flex-direction:column;
}

.toGo, .toStay {
  height: 50px;
  width: 100%;
  background: coral;
  transition: all 1000ms ease-in-out;
  overflow: hidden;
  clip-path:polygon(0 0,100% 0,100% 100%, 0 100%);
}

.toStay {
  margin: 12px 0;
}

.animate {
  height: 0;
  opacity: 0;
  clip-path:polygon(0 0,0% 0,0% 100%, 0 100%);
}
<div class="toGo">
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tristique sed nisi id aliquet. Etiam mauris diam, commodo in nisl ac, porttitor auctor mi. Nunc et blandit lacus. Donec facilisis dolor in arcu convallis, eu molestie magna placerat. Etiam blandit diam vitae nibh sollicitudin, ac gravida risus convallis. Nunc aliquet, turpis ac dignissim mollis, nulla nisi cursus leo, quis viverra nisi augue eget leo. Curabitur porta faucibus vestibulum.
</div>
<div class="toStay">Lorem Ipsum</div>

<p>Click on the first div</p>

You can adjust the clip-path to control how the animation is done.

const div = document.querySelector('.toGo');

div.addEventListener('click', event => {
  div.className += ' animate';
  
  // Simulate Angular's DOM modification
  setTimeout(() => div.style.display = 'none', 1100);
  setTimeout(() => div.style.display = 'block', 1200);
  setTimeout(() => div.className = 'toGo', 1300);
});
body {
  display:flex;
  flex-direction:column;
}

.toGo, .toStay {
  height: 50px;
  width: 100%;
  background: coral;
  transition: all 1000ms ease-in-out;
  overflow: hidden;
  clip-path:polygon(0 0,100% 0,100% 100%, 0 100%);
}

.toStay {
  margin: 12px 0;
}

.animate {
  height: 0;
  opacity: 0;
  clip-path:polygon(50% 0,50% 0,50% 100%, 50% 100%);
}
<div class="toGo">
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tristique sed nisi id aliquet. Etiam mauris diam, commodo in nisl ac, porttitor auctor mi. Nunc et blandit lacus. Donec facilisis dolor in arcu convallis, eu molestie magna placerat. Etiam blandit diam vitae nibh sollicitudin, ac gravida risus convallis. Nunc aliquet, turpis ac dignissim mollis, nulla nisi cursus leo, quis viverra nisi augue eget leo. Curabitur porta faucibus vestibulum.
</div>
<div class="toStay">Lorem Ipsum</div>

<p>Click on the first div</p>


来源:https://stackoverflow.com/questions/55045571/smooth-shrinking-animation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!