简体   繁体   English

如何使 CSS 变换影响其他元素的流动

[英]How to make a CSS transform affect the flow of other elements

I'm using CSS transitions with the transform property to shrinks elements when adding and removing them.我在添加和删除元素时使用带有transform属性的 CSS 转换来缩小元素。

However one problem with this is that this property doesn't affect the flow of other elements, so it appears as though the element being deleted shrinks away, and then the rest of the elements jump suddenly.但是有一个问题是这个属性不影响其他元素的流动,所以看起来好像被删除的元素缩小了,然后其余的元素突然跳了起来。

If I were to animate the height property instead of using a transform this would be fine, however in actual usage I am using elements of variable height so I won't know what heights I can animate between.如果我要为 height 属性设置动画而不是使用变换,这会很好,但是在实际使用中,我使用的是可变高度的元素,所以我不知道我可以在哪些高度之间设置动画。


Edit: people have suggested animating the height property (which won't work as stated above), or the max-height property.编辑:人们建议对height属性(如上所述不起作用)或max-height属性设置动画。 The max-height property will work to some extent, however you cannot align the timings perfectly as the transition will keep adjusting the max-height property past the actual height of the element until the end of the transition time. max-height属性会在一定程度上起作用,但是您不能完美地对齐时间,因为过渡将不断调整max-height属性超过元素的实际高度,直到过渡时间结束。

Another problem with these approaches is that it does not use the smooth animations that you can achieve with the transform property.这些方法的另一个问题是它没有使用可以通过transform属性实现的平滑动画。 The object's transform will happen smoothly, however the movement of the following elements will stutter as the browser renders these transitions differently.对象的变换会顺利进行,但是随着浏览器以不同方式呈现这些过渡,以下元素的移动会断断续续。


Here's a JSFiddle with what I mean (try adding then removing elements, and see the jump when elements are removed):这是我的意思的 JSFiddle(尝试添加然后删除元素,并在删除元素时查看跳转):

 var button = document.querySelector("button"); var box = document.createElement("div"); box.className = "box"; box.appendChild(document.createTextNode("Click to delete")); button.addEventListener("click", function(e) { var new_box = box.cloneNode(true); new_box.addEventListener("click", function(e) { this.className = "box deleting"; window.setTimeout(function(e) { new_box.remove(); }, 1000); }); this.parentNode.appendChild(new_box); });
 button { font-size: 20pt; } .box { font-size: 20pt; margin: 10px; width: 200px; padding: 10px; background: pink; transform: scale(1, 1); transform-origin: top left; } .deleting { transform: scale(1, 0); transition: all 1000ms ease; }
 <button> Add Box </button>

For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element.对于布局由 CSS 框模型控制的元素,transform 属性不会影响围绕已转换元素的内容流。

REF: Transform Rendering REF:变换渲染

You will have to use the max-height property ( check this answer ) to get the desired effect.您必须使用max-height属性( 检查此答案)才能获得所需的效果。

 var button = document.querySelector("button"); var box = document.createElement("div"); box.className = "box"; box.appendChild(document.createTextNode("Click to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to deleteClick to delete")); button.addEventListener("click", function(e) { var new_box = box.cloneNode(true); new_box.style.height = ( Math.random() * (200 - 30) + 30 ) + 'px'; new_box.addEventListener("click", function(e) { this.className = "box deleting"; window.setTimeout(function(e) { new_box.remove(); }, 1000); }); this.parentNode.appendChild(new_box); });
 button { font-size: 20pt; } .box { overflow:hidden; font-size: 12pt; margin-bottom: 10px; width: 600px; max-height:1000px; padding: 10px; background: pink; transform: scaleY(1); transform-origin: top left; } .deleting { transform: scaleY(0); max-height:0; padding:0 10px; margin-bottom:0; transition: padding 1000ms ease,max-height 1000ms ease, transform 500ms ease 500ms, margin-bottom 1000ms ease; }
 <button> Add Box </button>

There's no way to do it right (with css alone) ¬¬没有办法做对(仅使用 css) ¬¬

The way I did it was partially using JS (or C#/Blazor in my case)我这样做的方式是部分使用 JS(或在我的情况下使用 C#/Blazor)

I used the max-height but I set it with a var() , and the value itself I'm calculating based on the content that I have (I'm using JS/c# for that), then use that value to set an inline style withe the css variable:我使用了max-height但我用var()设置了它,并且我正在根据我拥有的内容计算值本身(我使用的是 JS/c#),然后使用该值设置一个带有 css 变量的内联style

<ul 
    class="submenu @SubMenuActiveClass" 
    style="--max-height:@((int)(40.3f * Model.Children.Count))px">

    <!--... childrens with 40.3px height each -->

</ul>
.submenu {
    max-height: 0;
    transition: max-height 0.3s ease-out;
    overflow: hidden;

    &.active {
        max-height: var(--max-height);
    }
}

The example is in Blazor and SCSS but it's quite easy to understand该示例在 Blazor 和 SCSS 中,但很容易理解

You could create a wrapper around the shrinking boxes.您可以在缩小的盒子周围创建一个包装器。 Now you're just scaling the red boxes, that means it still uses the same space, but it's rendered in a scaled way.现在你只是缩放红色框,这意味着它仍然使用相同的空间,但它以缩放的方式呈现。 When you finally delete it, it doesn't use that space anymore, the elements under it will jump upwards.当你最终删除它时,它不再使用那个空间,它下面的元素会向上跳。

If you create a wrapper around each red box, you can control the space it takes.如果您在每个红色框周围创建一个包装器,您就可以控制它占用的空间。 Just change the height of that wrapper, with a transition too.只需更改该包装器的高度,也可以进行过渡。

/* css for a wrapper */
overflow: hidden;
transition: height .2s; /* your time */

So, don't only scale the red boxes with a transition, but also put them in a wrapping element, and change that element's height.所以,不要只用过渡来缩放红色框,还要把它们放在一个环绕元素中,并改变该元素的高度。

For the best affect, you will need to modify the boxing properties which affect its surroundings.为了获得最佳效果,您需要修改影响其周围环境的拳击属性。 This includes the width/height, padding, margins, and border width.这包括宽度/高度、填充、边距和边框宽度。 In the below example, I set the relevant properties to 0 for your desired effect.在下面的示例中,我将相关属性设置为0以获得所需的效果。 This includes all properties which affect the vertical spacing of the element: height , padding-[top/bottom] , margin-[top/bottom] , and border-[top/bottom]-width are all transitioned to 0.这包括影响元素垂直间距的所有属性: heightpadding-[top/bottom]margin-[top/bottom]border-[top/bottom]-width都转换为 0。

I also added box-sizing: border-box;我还添加了box-sizing: border-box; and overflow: hidden;overflow: hidden; to the box - you should see what happens when those are not set.到框中 - 您应该看到未设置时会发生什么。 I'll let you learn about those on your own.我会让你自己了解这些。

 var button = document.querySelector("button"); var box = document.createElement("div"); box.className = "box"; box.appendChild(document.createTextNode("Click to delete")); button.addEventListener("click", function(e) { var new_box = box.cloneNode(true); new_box.addEventListener("click", function(e) { new_box.style.height = this.offsetHeight + 'px'; window.requestAnimationFrame(function () { new_box.style.height = 0; new_box.className = "box deleting"; window.setTimeout(function(e) { new_box.remove(); }, 1000); }); }); this.parentNode.appendChild(new_box); });
 button { font-size: 20pt; } .box { box-sizing: border-box; overflow: hidden; font-size: 20pt; margin: 10px; width: 200px; padding: 10px; border: 5px solid red; background: pink; transform: scale(1, 1); transform-origin: top left; } .deleting { height: 0; padding-top: 0; padding-bottom: 0; margin-top: 0; margin-bottom: 0; border-top-width: 0; border-bottom-width: 0; transform: scale(1, 0); transition: all 1000ms ease; }
 <button> Add Box </button>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM