Что вызывает скачок во время этого коллапса или расширения CSS перехода? - PullRequest
3 голосов
/ 11 января 2020

Я понимаю, что есть CSS / JS библиотеки анимации, которые могли бы выполнить sh, но я изучаю CSS Transitions и хотел бы выполнить sh с минимальным JS. (Мне очень нравится CSS:)

У меня есть несколько столбцов flex-item одинакового размера с flex-grow: 1. Я бы хотел щелкнуть заголовок столбца, чтобы уменьшить или развернуть столбец, сам заголовок должен оставаться видимым (чтобы его можно было щелкнуть, чтобы развернуть). Поскольку display не является анимируемым свойством CSS, я пытаюсь сделать это с 2-секундным переходом на width: 0; opacity: 0; для содержимого flex-элемента (кроме заголовка) и flex-grow: 0 на самом flex-item.

Я пытаюсь устранить нежелательный «прыжок» в конце коллапса и в начале расширения.

Несмотря на одинаковую продолжительность и предположительно стрельбу в одно и то же время (после урока изменение при щелчке), кажется, что переход flex-grow не синхронизирован с переходом ширины / непрозрачности содержимого, и поэтому переход flex-grow завершается «слишком рано» (до того, как содержимое станет шириной 0), а затем переходит к последнему бит после окончания ширины перехода. Если я сделаю переход гибкого роста длиннее (чем переход ширины) и задержу его, скачок уменьшится.

Я пытаюсь понять точное взаимодействие, чтобы устранить скачок без магического хакерства c числа .

Вот кодовая ручка: 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>

Если это поможет донести цель, мой вариант использования - это календарь в виде недели, где указаны дни (Пн, т. Д. c) .) это столбцы.

Ответы [ 2 ]

1 голос
/ 11 января 2020

Я полагаю, что проблема связана с 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>
0 голосов
/ 11 января 2020

Краткий ответ:

На вашем .collapsed div (около строки 46 в вашем коде) измените:

width: 0

на

width: 0%

...