我正在尝试实现一个表(目前基于 CSS 网格),其中一行是隐藏的。单击某处后,该行应平滑展开。我希望此行的内容在动画期间可见并保持其正确大小。
这与 this demo 非常相似,但我没有实现菜单。但事实上,在该演示中,内容(“菜单项 1”、“菜单项 2”、...)在动画期间具有恒定大小,这是我想要的。
我想使用 FLIP technique as described here 来实现它轻松实现高帧率。
我在行上添加了 scaleY(0.01)
,在内部包装器上添加了 scaleY(100)
,希望它们能够相互抵消并保持比例.我还添加了 transform-origin: 0 0
希望动画行的上边缘在动画期间保持在同一个位置。
但是,内容最初太高了。它们似乎也在沿 Y 轴移动,即使我设置了 transform-origin: 0 0
(但这可能只是不正确高度的影响)。
我尝试使用 Element.animate()
以及手动 element.style.transform = ...
方法,但均无济于事。
我的问题:为什么隐藏的行没有正确地设置动画(其内容的高度不是恒定的,它们似乎沿 Y 轴移动)?如何解决这个问题?
let collapsed = Array.from(document.querySelectorAll(".collapsed"));
collapsed.forEach((row, idx) => {
row.dataset["collapsedIdx"] = idx;
document.querySelector("label").addEventListener("click", () => {
let collapsedSelf = row.getBoundingClientRect();
let rowsBelow = Array.from(
row.parentElement.querySelectorAll(`[data-collapsed-idx='${idx}'] ~ *`)
);
row.classList.remove("collapsed");
let expandedSelf = row.getBoundingClientRect();
let diffY = expandedSelf.height - collapsedSelf.height;
let animationTiming = {
duration: 2000,
easing: "linear"
};
let wrapper = row.querySelector(":scope > *");
row.animate(
[{ transform: `scaleY(0.01)` }, { transform: `scaleY(1)` }],
animationTiming
);
wrapper.animate(
[{ transform: `scaleY(100) ` },
{ transform: `scaleY(1) ` }],
animationTiming
);
rowsBelow.forEach((rowBelow) => {
rowBelow.animate([
{ transform: `translateY(-${diffY}px)` },
{ transform: `translateY(0)` }
], animationTiming);
});
});
});
* {
box-sizing: border-box;
}
section {
display: grid;
grid-template-columns: max-content 1fr;
}
.subsection {
grid-column: span 2;
}
label, p {
display: block;
margin: 0;
}
.collapsible,
.collapsible > * {
transform-origin: 0 0;
will-change: transform;
contain: content;
}
.collapsed {
height: 0;
overflow: hidden;
}
/* .collapsed {
transform: scaleY(.2);
}
.collapsed > * {
transform: scaleY(5)
}
*:nth-child(8),
*:nth-child(9),
*:nth-child(10),
*:nth-child(11),
*:nth-child(12) { transform: translateY(-35px); }
*/
/* .animate-on-transforms {
transition: transform 2000ms linear;
} */
<section>
<label><strong>CLICK ME!!!</strong></label>
<p>Value 1</p>
<label>Row 2</label>
<p>Value 2</p>
<label>Row 3</label>
<p>Value 3</p>
<div class="subsection collapsible collapsed">
<section>
<label>Subrow 1</label>
<p>Subvalue 1</p>
<label>Subrow 2</label>
<p>Subvalue 2</p>
<label>Subrow 3</label>
<p>Subvalue 3</p>
<label>Subrow 4</label>
<p>Subvalue 4</p>
</section>
</div>
<label>Row 4</label>
<p>Value 4</p>
<label>Row 5</label>
<p>Value 5</p>
</section>
最佳答案
我认为这里的问题是插值。你假设在动画的每一步我们总是有 scale(x)
和 scale(1/x)
其中 x
在 [0,1]
但由于四舍五入,我认为你不会有这个。
这是一个基本的例子:
.box,
p{
transform-origin:0 0;
transition:1s linear;
}
.box:hover {
transform:scale(0.1);
}
.box:hover p{
transform:scale(10);
}
<div class="box">
<p>
Lorem Ipsume<br>
Lorem Ipsume<br>
Lorem Ipsume<br>
Lorem Ipsume<br>
Lorem Ipsume<br>
</p>
</div>
从逻辑上讲,我们可能认为文本会保持不变,但事实并非如此。它会增长然后再次收缩。所以是的,比例会被取消,但不会沿着动画。
关于css - 为什么这个动画不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54406055/