web-dev-qa-db-fra.com

est-il possible d'animer des insertions et des suppressions de flexbox

Lorsque je supprime un élément d'une boîte flexible, les éléments restants "s'emboîtent" dans leurs nouvelles positions immédiatement plutôt que de l'animer.

Sur le plan conceptuel, étant donné que les éléments changent de position, je pense que les transitions s'appliqueront.

J'ai défini la propriété de transition sur tous les éléments impliqués (la flexbox et les enfants)

Est-il possible d'animer des modifications (ajouts et suppressions) à une flexbox? Il s’agit en réalité d’une étape décisive pour moi et de la pièce manquante avec flexbox.

36
mmaclaurin

J'ai corrigé la démo de @ skyline3000 d'après cet exemple de Treehouse . Je ne sais pas si cela va casser à nouveau si les navigateurs changent, mais cela semble être le moyen prévu pour animer les changements de taille flex:

http://jsfiddle.net/2gbPg/2/

J'ai aussi utilisé jQuery mais techniquement, ce n'est pas obligatoire.

.flexed {
    background: grey;
    /* The border seems to cause drawing artifacts on transition. Probably a browser bug. */
    /* border: 1px solid black; */
    margin: 5px;
    height: 100px;
    flex-grow: 1;
    transition: flex-grow 1000ms linear;
}

.removed {
    /* Setting this to zero breaks the transition */
    flex-grow: 0.00001;
}

Une chose à noter à propos du CSS est que vous ne pouvez pas passer à un flex-grow de zéro, il ne le fera pas, il disparaîtra tout simplement. Vous devez simplement mettre une très petite valeur. De plus, il semble y avoir un bogue d'artefact lors du tracé des bordures. J'ai donc utilisé un arrière-plan dans ce cas.

21
Chris Nicola

N'oubliez pas que les spécifications de modèle de boîte flexible et de disposition de la grille changent constamment, même les propriétés et les valeurs valides. Les implémentations du navigateur sont également loin d’être terminées. Cela dit, vous pouvez passer de la propriété flex à la transition en douceur des éléments, puis écoutez TransitionEnd pour supprimer définitivement le nœud de l’arborescence DOM.

Voici un exemple de JSFiddle, fonctionnant dans Chrome 21: http://jsfiddle.net/5kJjM/ (cliquez sur le div du milieu)

var node = document.querySelector('#remove-me');

node.addEventListener('click', function(evt) {
  this.classList.add('clicked');
}, false);

node.addEventListener('webkitTransitionEnd', function(evt) {
  document.querySelector('#flexbox').removeChild(this);
}, false);
#flexbox {
  display: -webkit-flex;
  -webkit-flex-flow: row;
}

.flexed {
  border: 1px solid black;
  height: 100px;
  -webkit-flex: 1 0 auto;
  -webkit-transition: -webkit-flex 250ms linear;
}

.clicked {
  -webkit-flex: 0 0 auto;
}
<div id="flexbox">
  <div class="flexed"></div>
  <div class="flexed" id="remove-me"></div>
  <div class="flexed"></div>
</div>

Edit: Pour préciser, lorsque vous supprimez un nœud, vous devez définir son flex sur 0, puis le supprimer du DOM. Lorsque vous ajoutez un nœud, ajoutez-le avec flex: 0, puis faites-le passer à flex: 1

11
skyline3000

Je l'ai accidentellement fait fonctionner de manière simple… .. En gros, vous définissez width:0;flex-grow:1 et bien sûr vous ajoutez transition:all 2s; et c'est tout. C'est un hack curieux.

Voir le travail

1

J'ai créé un code qui anime les éléments lorsque vous en supprimez un, jetez un oeil à: https://codepen.io/MauriciAbad/pen/eQoQbK } _

Il peut être optimisé, mais fonctionne. ;RÉ

HTML

<div class="container">
    <div id="0"></div>
    <div id="1"></div>
    ... more divs ...
</div>

CSS

.container{
    display: flex;
    flex-wrap: wrap;
}
.container > div{
    flex-grow: 1;
    transform-Origin: left top;
}

JavaScript

var cards = document.querySelectorAll('.container > div');
cards.forEach((card) => {
    card.addEventListener('click', () => {removeCard(card);});
});

var cardsOldInfo = //example content
    {"cardId": {
        "x": 100,
        "y": 200,
        "width": 100
        }
    };
var cardsNewInfo = cardsOldInfo;

function removeCard(card){
    cardsOldInfo = getCardsInfo();
    card.parentNode.removeChild(card);
    cardsNewInfo = getCardsInfo();
    moveCards();
}

function getCardsInfo(){
    updateCards();
    let cardsInfo = {};
    cards.forEach((card) => {
        var rect = card.getBoundingClientRect();
        cardsInfo[card.id] = {
            "x": rect.left,
            "y": rect.top,
            "width": (rect.right - rect.left)
        };
    });
    return cardsInfo;
}

function moveCards(){
    updateCards();
    cards.forEach((card) => {
        card.animate([ 
            {
                transform: `translate(${cardsOldInfo[card.id].x - cardsNewInfo[card.id].x}px, ${cardsOldInfo[card.id].y -cardsNewInfo[card.id].y}px) scaleX(${cardsOldInfo[card.id].width/cardsNewInfo[card.id].width})`
            }, 
            {
                transform: 'none'
            }
        ], { 
            duration: 250,
            easing: 'ease-out'
        });
        });
}

function updateCards(){
  cards = document.querySelectorAll('.container > div');
}

J'ai essayé d'animer des lignes dans ma flexbox. Ce n'était pas possible simplement en CSS. Je l’ai donc fait avec un peu de javascript et un parent supplémentaire pour mes rangées de flexbox.

HTML: 

<div class="outer-container">
  <div class="inner-container">
    <div class="row">Row number 1</div>
  </div>
</div>

<button id="add">Add one more item</button>

CSS: 

.row{
  height : 40px;
  width : 200px;
  border: 1px solid #cecece;
  text-align : center;
  padding-top : 20px;
}

.outer-container {
  height : 500px;
  border : 1px solid blue;
  width : 250px;
  display: flex;
  justify-content : center;
  align-items: center;
}

.inner-container { 
  height : 42px;
  transition : height 0.3s;
 }

button {
  width : 200px;
  height: 30px;
  margin-left : 80px;
  margin-top : 10px;
}

Javascript: 

(() => {
    let count = 1;
    document.querySelector("#add").addEventListener('click', () => {
        const template = document.createElement('div');
        count += 1;
        template.textContent = `Row number ${count}`;
        template.className = 'row';

        const innerContainer = document.querySelector('.inner-container');
        innerContainer.appendChild(template);
        innerContainer.style.height = `${innerContainer.clientHeight + 42}px`;
    })
})();

Démo de travail: https://jsfiddle.net/crapbox/dnx654eo/1/

0
crapbox