【问题标题】:CSS3 animate or transition elements into position after removal of an element above移除上面的元素后,CSS3 将元素设置为动画或过渡
【发布时间】:2017-06-20 00:10:31
【问题描述】:

在没有任何明显闪烁和任何奇怪现象的情况下实现这一目标的最佳方法是什么?

开始的小提琴:http://jsfiddle.net/35qec14b/2/

$('.element').on('click', function(e){
  this.remove();
});
.element {
  position:relative;
  width: 200px;
  margin:5px;
  padding:20px;
  cursor:pointer;
  background: rgb(150,200,250);
  transition:1s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
(click to remove)
<div class="element">Element 1</div>
<div class="element">Element 2<br>Second line</div>
<div class="element">Element 3</div>
<div class="element">Element 4<br>Second line</div>
<div class="element">Element 5</div>

注意:在这种情况下,被移除的元素必须立即消失,因为它会出现在另一个位置,我们不希望它同时在两个地方可见。

目前的想法:

  • transform:translateY 用于已删除元素下方的所有元素(对于大型列表可能会占用大量性能)
  • 动画/变换下面第一个元素的ma​​rgin,从移除元素的高度到0(利用链式动画?step-start?)
  • 用透明占位符替换已移除的元素,并将其自己的 height 设置为 0

【问题讨论】:

    标签: css animation css-animations


    【解决方案1】:

    想到的最好方法是隐藏它,将其克隆到新位置(此处未显示),然后为其高度设置动画

    当同时为边距、内边距和高度设置动画时,它会变得不那么平滑,所以我为内容添加了一个额外的内部包装,因此动画只为高度设置动画

    $('.element').on('click', function(e) {
      this.style.height = $(this).height()+ 'px';
      this.classList.add('hide-me');
      (function(el) {
        setTimeout(function() {
          el.remove();
        }, 500);
      })(this);
    });
    .element {
      position: relative;
      width: 200px;
      overflow: hidden;
    }
    .element > div {
      margin: 5px;
      padding: 20px;
      background: rgb(150, 200, 250);
    }
    
    .element.hide-me {
      animation: hideme .5s forwards;
      opacity: 0;
    }
    @keyframes hideme {
      100% {
        height: 0;
      }
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    (click to remove)
    <div class="element">
      <div>
        Element 1
      </div>
    </div>
    <div class="element">
      <div>
        Element 2
        <br>Second line
      </div>
    </div>
    <div class="element">
      <div>
        Element 3
      </div>
    </div>
    <div class="element">
      <div>
        Element 4
        <br>Second line
      </div>
    </div>
    <div class="element">
      <div>
        Element 5
      </div>
    </div>

    【讨论】:

    • 感谢 LG 儿子。我看到元素和滚动条上有某种非常快速的闪烁。您认为这种方法可以可靠地预防吗?
    • 不,但我认为我通过将动画时间设置为更高的值来隔离问题:jsfiddle.net/usdut3um/2
    • 动画在 /3 版本中是平滑的,但平滑度修复依赖于固定高度,在我的情况下无法修复。不过,我会尝试使用您的方法。我想如果我将删除的项目替换为JS的占位符(在我的情况下元素将被拖出,所以它不能等待动画)然后闪烁应该解决。
    • @Alph.Dev 我制作了另一个版本,动态设置高度,但它不起作用,原因如下:stackoverflow.com/questions/10619998/…
    • @Alph.Dev 想通了...使用animation而不是transition ...更新了我的答案
    【解决方案2】:

    这是使用 .animate() 的 jQuery 方法

    $('.element').on('click', function(e){
      var $this = $(this), $next = $this.next();
      $next.css({
        marginTop: $this.outerHeight(true)
      }).animate({
        marginTop: 5
      }, 200);
      $this.remove();
    });
    .element {
      position:relative;
      width: 200px;
      margin:5px;
      padding:20px;
      cursor:pointer;
      background: rgb(150,200,250);
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    (click to remove)
    <div class="element">Element 1</div>
    <div class="element">Element 2<br>Second line</div>
    <div class="element">Element 3</div>
    <div class="element">Element 4<br>Second line</div>
    <div class="element">Element 5</div>

    这是一种 CSS 过渡方法

    $('.element').on('click', function(e){
      var $this = $(this), $next = $this.next();
      $next.css({
        marginTop: $this.outerHeight(true)
      });
      setTimeout(()=>{
        $next.addClass('hide');
        setTimeout(()=>{
          $next.css({marginTop: ''}).removeClass('hide');
        }, 250)
      }, 20);
      $this.remove();
    });
    .element {
      position:relative;
      width: 200px;
      margin:5px;
      padding:20px;
      cursor:pointer;
      background: rgb(150,200,250);
    }
    
    .element.hide {
      transition: margin-top 0.25s linear;
      margin-top: 5px !important;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    (click to remove)
    <div class="element">Element 1</div>
    <div class="element">Element 2<br>Second line</div>
    <div class="element">Element 3</div>
    <div class="element">Element 4<br>Second line</div>
    <div class="element">Element 5</div>

    【讨论】:

    • 感谢您并排提供两种方法。使用transition:margin-top的那个在我的浏览器上没有动画,你能看看吗?
    • @Alph.Dev 你用的是什么浏览器?可能是 ecmascript 6 箭头函数,也可能是 transition 需要前缀,但如果不知道您使用的是什么浏览器和版本,就很难分辨。
    • 它在 Chrome 59 中工作,但 FF 54 给出了意想不到的结果。奇怪的是,有时它在 FF 中也有动画,但大多数时候没有流畅的动画。只是一个跳跃。
    • @Alph.Dev 看起来可能是我穷人的请求动画帧。只使用 raq 可能会更好,但为了兼容性,我只是在第一次超时中添加了 20 毫秒的值。看看这是否适用于 FF54。
    • 成功了!你能解释一下那里发生了什么吗?为什么会滞后,为什么添加超时有帮助?
    【解决方案3】:

    尽管您担心使用转换可能会产生负面影响,但我认为情况正好相反。

    请记住,其他解决方案涉及大量回流,这可能对 CPU 的性能要求更高(转换很可能由 GPU 处理)。

    但是,使用转换解决这个问题有点难以编码。专门改变需要移动的像素数量,并注入到样式中。

    查看可行的解决方案。我只使用了 JS 来使其更便携。

    如果您担心性能,可以将 findKeyframesRule 的结果分配给变量并重复使用。

    document.addEventListener('DOMContentLoaded', setEvent, false);
    
    function setEvent() {
      var elements = document.getElementsByClassName('element');
    
      for (var n = 0; n < elements.length; n++) {
        elements[n].addEventListener('click', remove, false);
      }
    }
    
    function remove(event) {
      var current = event.currentTarget;
      var elements = document.getElementsByClassName('move');
      for (var n = 0; n < elements.length; n++) {
        elements[n].classList.remove('move');
      }
      window.setTimeout(function() {
        remove2(current);
      }, 0);
    }
    
    function remove2(current) {
      var next = current.nextElementSibling;
      if (!next) {
        return;
      }
      var top1 = current.offsetTop;
      var top2 = next.offsetTop;
      var diff = top2 - top1;
      var newTransform = 'translateY(' + diff + 'px)';
    
      var rule = findKeyframesRule('move');
      var style = rule.cssRules[0].style;
      style.transform = newTransform;
      next.classList.add('move');
      current.style.height = '0px';
    }
    
    function findKeyframesRule(rule) {
      // gather all stylesheets into an array
      var ss = document.styleSheets;
    
      // loop through the stylesheets
      for (var i = 0; i < ss.length; i++) {
    
        var ss1 = ss[i];
        // loop through all the rules
        if (!ss1.cssRules) {
          alert('you are using Chrome in local files');
          return null;
        }
        for (var j = 0; j < ss1.cssRules.length; j++) {
    
          // find the keyframe rule whose name matches our passed parameter
          if (ss1.cssRules[j].type == window.CSSRule.KEYFRAMES_RULE && ss1.cssRules[j].name == rule)
            return ss1.cssRules[j];
        }
      }
      return null;
    }
    .element {
      position: relative;
      width: 200px;
      overflow: hidden;
    }
    
    .element>div {
      margin: 5px;
      padding: 20px;
      background: rgb(150, 200, 250);
    }
    
    .move,
    .move~.element {
      animation: move 2s;
    }
    
    @keyframes move {
      from {
        transform: translateY(60px);
      }
      to {
        transform: translateY( 0px);
      }
    }
    (click to remove)
    <div class="element">
      <div>
        Element 1
      </div>
    </div>
    <div class="element">
      <div>
        Element 2
        <br>Second line
      </div>
    </div>
    <div class="element">
      <div>
        Element 3
      </div>
    </div>
    <div class="element">
      <div>
        Element 4
        <br>Second line
      </div>
    </div>
    <div class="element">
      <div>
        Element 5
      </div>
    </div>

    【讨论】:

      猜你喜欢
      • 2013-08-24
      • 2012-05-16
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 2017-03-28
      • 1970-01-01
      • 2011-04-27
      相关资源
      最近更新 更多