CSS 是否可以为 flexbox 插入和删除设置动画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11106876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 04:14:19  来源:igfitidea点击:

is it possible to animate flexbox inserts & removes?

csscss-transitionscss-animationsflexbox

提问by mmaclaurin

When I remove an item from a flexbox, the remaining items "snap" into their new positions immediately rather than animating.

当我从 flexbox 中移除一个项目时,剩余的项目会立即“对齐”到它们的新位置而不是动画。

Conceptually, since the items are changing their positions, I would expect the transitions to apply.

从概念上讲,由于项目正在改变它们的位置,我希望过渡适用。

I have set the transition property on all involved elements (the flexbox and the children)

我已经在所有涉及的元素(弹性盒和子元素)上设置了过渡属性

Is there any way to animate edits (adds & deletes) to a flexbox? This is actually a showstopper for me and the one missing piece with flexbox.

有没有办法对 flexbox 进行动画编辑(添加和删除)?这对我来说实际上是一个亮点,也是 flexbox 的一个缺失部分。

回答by Chris Nicola

I've fixed up @skyline3000's demo based on this example from Treehouse. Not sure if this will break again if browsers change but this seems to be the intended way to animate flex size changes:

我已经根据Treehouse 的这个例子修复了@skyline3000 的演示。不确定如果浏览器更改,这是否会再次中断,但这似乎是动画 flex 大小更改的预期方式:

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

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

Also I used jQuery but it technically isn't required.

我也使用了 jQuery,但在技术上不是必需的。

.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;
}

One thing to note about the CSS is you can't transition to a flex-growof zero, it won't transition it will just disappear. You need to just put a very small value. Also there seems to be an artifacting bug when drawing borders so I've used a background in this case.

关于 CSS 需要注意的一件事是你不能过渡到flex-grow零,它不会过渡它会消失。你只需要输入一个非常小的值。绘制边框时似乎还有一个人工错误,所以我在这种情况下使用了背景。

回答by skyline3000

Remember that the Flexible Box Model and Grid Layout specifications are changing constantly, even the properties and valid values. The browser implementations are far from complete as well. That being said, you can transition on the flexproperty so that the elements transition smoothly, then just listen for TransitionEndto finally remove the node from the DOM tree.

请记住,Flexible Box Model 和Grid Layout 规范在不断变化,甚至包括属性和有效值。浏览器的实现也远未完成。话虽如此,您可以在flex属性上进行过渡,以便元素平滑过渡,然后只需监听TransitionEnd最终从 DOM 树中删除节点即可。

Here is an example JSFiddle, running in Chrome 21: http://jsfiddle.net/5kJjM/(click the middle div)

这是一个在 Chrome 21 中运行的 JSFiddle 示例:http: //jsfiddle.net/5kJjM/(单击中间的 div)

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: To further clarify, when you remove a node, you should set its flex to 0, then remove it from the DOM. When adding a node, add it in with flex: 0, then transition it to flex:1

编辑:为了进一步澄清,当您删除一个节点时,您应该将其 flex 设置为 0,然后将其从 DOM 中删除。添加节点时,将其添加到 flex:0,然后将其转换为 flex:1

回答by John Balvin Arias

I accidentally got it to work in a simple way. Basically, you set width:0;flex-grow:1and of course add transition:all 2s;and that's it. It's a curious hack.

我不小心让它以一种简单的方式工作。基本上,你设置width:0;flex-grow:1,当然添加transition:all 2s;,就是这样。这是一个奇怪的黑客。

See it working

看到它工作

回答by Maurici Abad

I've done a codepen that animates the elements when you remove one, take a look: https://codepen.io/MauriciAbad/pen/eQoQbK

我做了一个代码笔,当你删除一个元素时,它会为元素设置动画,看看:https://codepen.io/MauriciAbad/pen/eQoQbK

It can be optimized, but works. ;D

它可以优化,但有效。;D

HTML

HTML

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

CSS

CSS

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

JavaScript

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');
}

回答by Alec

Another adaptation to @skyline3000 and @chris-nicola's solutions: http://jsfiddle.net/2gbPg/2/

对@skyline3000 和@chris-nicola 解决方案的另一种改编:http: //jsfiddle.net/2gbPg/2/

You can simply animate max-width(or max-heightas appropriate), animating to 0when removing, and 100%when inserting.

您可以简单地设置动画max-width(或max-height视情况而定)、0在移除和100%插入时设置动画。

回答by crapbox

I have been trying to animate rows in my flexbox. This was not possible through just css. So I did it with a bit of javascript and an extra parent for my flexbox rows.

我一直在尝试为 flexbox 中的行设置动画。这仅通过 css 是不可能的。所以我用一些 javascript 和一个额外的父级来做我的 flexbox 行。

HTML :

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 :

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 :

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`;
    })
})();

Working demo : https://jsfiddle.net/crapbox/dnx654eo/1/

工作演示:https: //jsfiddle.net/crapbox/dnx654eo/1/