是否有可能为flexbox插入和删除动画?

mma*_*rin 41 css3 flexbox css-transitions css-animations

当我从flexbox中移除一个项目时,其余项目会立即"捕捉"到新位置而不是动画.

从概念上讲,由于项目正在改变其位置,我希望过渡适用.

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

有没有办法为Flexbox编辑(添加和删除)动画?这对我来说实际上是一个showstopper,而且是flexbox的一个缺失部分.

Chr*_*ola 24

我已经根据Treehouse的这个例子修复了@ skyline3000的演示.如果浏览器发生变化,不确定这是否会再次中断,但这似乎是设置弹性尺寸变化动画的预期方式:

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

我也使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这似乎只有在没有内容的情况下才有效,这似乎......不太可能.(例如在div中加入一些文字) (7认同)
  • **注意:**它现在可以与`flex-grow:0`一起使用 (2认同)

sky*_*000 11

请记住,Flexible Box模型和网格布局规范会不断变化,甚至是属性和有效值.浏览器的实现还远未完成.话虽这么说,你可以在flex属性上进行转换,以便元素平滑过渡,然后只是监听TransitionEnd最终从DOM树中删除节点.

这是一个在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);
Run Code Online (Sandbox Code Playgroud)
#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;
}
Run Code Online (Sandbox Code Playgroud)
<div id="flexbox">
  <div class="flexed"></div>
  <div class="flexed" id="remove-me"></div>
  <div class="flexed"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

编辑:为了进一步说明,删除节点时,应将其flex设置为0,然后将其从DOM中删除.添加节点时,使用flex:0添加节点,然后将其转换为flex:1

  • 我在演示中找不到任何转换...它就像普通的flex一样......并且demo中的`transitionEnd`处理程序没有触发,这意味着没有应用转换... (2认同)

Joh*_*ias 7

我无意中让它以一种简单的方式工作。基本上,您设置width:0;flex-grow:1并添加,仅transition:all 2s;此而已。这是一个奇怪的黑客行为。

看到它工作


Mau*_*rez 6

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

HTML

<div class="container">
    <div></div>
    <div></div>
    ... more elements ...
</div>
Run Code Online (Sandbox Code Playgroud)

CSS

.container{
    display: flex;
    flex-wrap: wrap;
}
.container > * {
    transform-origin: left top;
}
Run Code Online (Sandbox Code Playgroud)

TypeScript

If you want the JavaScript just remove the : Anything from the function's signature and the interface at the top.

interface FlexItemInfo {
  element: Element

  x: number
  y: number
  width: number
  height: number
}

const container = document.querySelector('.container')
for (const item of container.children) {
  item.addEventListener('click', () => {
    removeFlexItem(container, item)
  })
}

function removeFlexItem(container: Element, item: Element): void {
  const oldFlexItemsInfo = getFlexItemsInfo(container)
  container.removeChild(item)
  const newFlexItemsInfo = getFlexItemsInfo(container)

  aminateFlexItems(oldFlexItemsInfo, newFlexItemsInfo)
}

function getFlexItemsInfo(container: Element): FlexItemInfo[] {
  return Array.from(container.children).map((item) => {
    const rect = item.getBoundingClientRect()
    return {
      element: item,
      x: rect.left,
      y: rect.top,
      width: rect.right - rect.left,
      height: rect.bottom - rect.top,
    }
  })
}

function aminateFlexItems(
  oldFlexItemsInfo: FlexItemInfo[],
  newFlexItemsInfo: FlexItemInfo[]
): void {
  for (const newFlexItemInfo of newFlexItemsInfo) {
    const oldFlexItemInfo = oldFlexItemsInfo.find(
      (itemInfo) => itemInfo.element === newFlexItemInfo.element
    )

    const translateX = oldFlexItemInfo.x - newFlexItemInfo.x
    const translateY = oldFlexItemInfo.y - newFlexItemInfo.y
    const scaleX = oldFlexItemInfo.width / newFlexItemInfo.width
    const scaleY = oldFlexItemInfo.height / newFlexItemInfo.height

    newFlexItemInfo.element.animate(
      [
        {
          transform: `translate(${translateX}px, ${translateY}px) scale(${scaleX}, ${scaleY})`,
        },
        { transform: 'none' },
      ],
      {
        duration: 250,
        easing: 'ease-out',
      }
    )
  }
}
Run Code Online (Sandbox Code Playgroud)