【问题标题】:What is causing the jump during this collapse or expand CSS transition?在这种折叠或展开 CSS 过渡期间导致跳跃的原因是什么?
【发布时间】:2020-04-28 13:07:11
【问题描述】:

我知道有 CSS/JS 动画库可以实现这一点,但我正在学习 CSS 过渡,并希望用最少的 JS 来实现这一点。 (我很喜欢 CSS :)

我有几个与flex-grow: 1 大小相同的弹性项目列。我想单击列标题以缩小或展开列,标题本身应该保持可见(以便可以单击它来展开)。由于display 不是可动画的 CSS 属性,因此我尝试在 flex-item 内容(标题除外)上的 width: 0; opacity: 0; 和 flex-item 本身上的 flex-grow: 0 上进行 2 秒转换。

我正在尝试在折叠结束和展开开始时消除不受欢迎的“跳跃”。

尽管持续时间相同并且可能同时触发(在单击时更改类之后),但似乎 flex-grow 过渡与内容的宽度/不透明度过渡不同步,因此 flex-grow过渡“过早”完成(在内容为宽度 0 之前),然后在宽度过渡完成后跳转最后一位。如果我使 flex-grow 过渡更长(比宽度过渡)并延迟它,跳跃就会减少。

我试图了解确切的交互以消除没有幻数黑客的跳跃。

这是一个 CodePen:https://codepen.io/richardkmichael/pen/abzYOjB

document.querySelectorAll(".collapsible").forEach(function(c) {
  c.addEventListener("click", function(e) {
    this.classList.toggle("collapsed");
  });

  c.addEventListener("transitionrun", function(e) {
    this.classList.add("transitioning");
  });

  c.addEventListener("transitionend", function(e) {
    this.classList.remove("transitioning");

    // Set `display: none;` on contained div?
    // Perhaps unnecessary, since `width: 0`?
  });
});
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

p {
  margin: 1rem;
}

.container {
  outline: 1px solid blue;
  padding: 1rem;
  margin-bottom: 3rem;

  display: flex;
}

.collapsible {
  outline: 1px solid red;
  text-align: center;
  
  /* Lengthen transition and/or increase delay to remove jump. */
  /* Permits width/opacity transition to complete? */
  flex-grow: 1;
  transition: flex-grow 2.5s 0.5s;
}

.collapsible.collapsed {
  flex-grow: 0;
}

.collapsible div {
  outline: 1px solid green;

  opacity: 1;
  width: 100%;
  transition: opacity 2s, width 2s;
}

.collapsed div {
  outline: 1px solid purple;

  opacity: 0;

  width: 0;
  overflow: hidden;
  white-space: nowrap;
}

.transitioning div {
  /* Debugging. */
  background: cyan;

  /* Needed during transition to full-size. */
  overflow: hidden;
  white-space: nowrap;
}
<div class="container">
  
  <div class="collapsible">
    <h3>One</h3>
    <div>This is item 1.</div>
  </div>
  
  <div class="collapsible">
    <h3>Two</h3>
    <div>This is item 2.</div>
  </div>
  
</div>

<p>
  The aim is to smoothly eliminate the column content, leaving only the header.
</p>

<p>
  Click a column header ("One" or "Two") to collapse the column; click again to expand.</p>

<p>
  What is causing the jump near the end of the collapse or expand transition?
</p>

如果它有助于传达目标,我的用例是周视图中的日历,其中日期(星期一等)是列。

【问题讨论】:

    标签: css flexbox css-transitions


    【解决方案1】:

    我猜这个问题是由width:100% 引起的,更准确地说是使用百分比值创建复杂的计算来解决它。

    您可以尝试为max-width 设置动画。唯一的缺点是在使用大值时您会在开始时有延迟,但您可以调整过渡来纠正这个问题:

    document.querySelectorAll(".collapsible").forEach(function(c) {
      c.addEventListener("click", function(e) {
        this.classList.toggle("collapsed");
      });
    
      c.addEventListener("transitionrun", function(e) {
        this.classList.add("transitioning");
      });
    
      c.addEventListener("transitionend", function(e) {
        this.classList.remove("transitioning");
    
        // Set `display: none;` on contained div?
        // Perhaps unnecessary, since `width: 0`?
      });
    });
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    p {
      margin: 1rem;
    }
    
    .container {
      outline: 1px solid blue;
      padding: 1rem;
      margin-bottom: 3rem;
    
      display: flex;
    }
    
    .collapsible {
      outline: 1px solid red;
      text-align: center;
      
      /* Lengthen transition and/or increase delay to remove jump. */
      /* Permits width/opacity transition to complete? */
      flex-grow: 1;
      transition: flex-grow 2.5s 0.5s;
    }
    
    .collapsible.collapsed {
      flex-grow: 0;
    }
    
    .collapsible div {
      outline: 1px solid green;
    
      opacity: 1;
      max-width: 100vw;
      transition: opacity 2s, max-width 2s;
    }
    
    .collapsed div {
      outline: 1px solid purple;
    
      opacity: 0;
    
      max-width: 0;
      overflow: hidden;
      white-space: nowrap;
    }
    
    .transitioning div {
      /* Debugging. */
      background: cyan;
    
      /* Needed during transition to full-size. */
      overflow: hidden;
      white-space: nowrap;
    }
    <div class="container">
      
      <div class="collapsible">
        <h3>One</h3>
        <div>This is item 1.</div>
      </div>
      
      <div class="collapsible">
        <h3>Two</h3>
        <div>This is item 2.</div>
      </div>
      
    </div>
    
    <p>
      The aim is to smoothly eliminate the column content, leaving only the header.
    </p>
    
    <p>
      Click a column header ("One" or "Two") to collapse the column; click again to expand.</p>
    
    <p>
      What is causing the jump near the end of the collapse or expand transition?
    </p>

    【讨论】:

      【解决方案2】:

      简短的回答:

      在您的 .collapsed div 上(代码笔中的第 46 行附近)更改:

      width: 0

      width: 0%

      【讨论】:

      • 有趣,我通常指定无单位 0 所以没有尝试这个。现在,列的缩小宽度现在 [看起来是] 内容 div 的原始宽度,尽管它是 0。似乎最终的弹性项目大小是在浏览器知道内容 div 将是0 宽度之前计算出来的。感谢您的提示。
      猜你喜欢
      • 2016-10-01
      • 2023-04-10
      • 2012-07-15
      • 2021-05-11
      • 2010-11-29
      • 1970-01-01
      • 2018-12-21
      • 2020-01-13
      • 1970-01-01
      相关资源
      最近更新 更多