我有一个驻留在容器中的列表,该列表会定期从容器底部删除/添加项目。容器本身固定在视口的左下方。
添加一个新孩子后,我希望所有现有孩子向上滑动,而当一个孩子被移除时,其上方的所有兄弟姐妹都希望向下滑动。
我不知道要为列表元素transition
使用哪个属性。当我将transition: all ...;
应用于.toast
时,它会在附加一个孩子时正确设置向上滑动的动画效果,但不适用于移除孩子时的动画效果。
很明显,因为transition: all
可以工作,该属性可以设置动画,但是我不知道它是哪个属性。我尝试过transition: bottom
,{{1 }},height
和其他几个人,但他们并没有达到我想要的目标。我希望使用margin-bottom
避免,并且只想将transition: all
应用于必要的属性。
编辑:要明确的是,我不是在问如何为单个吐司进/出动画(即正在添加/删除的动画)设置动画,而是要如何控制已经存在的其他烤面包,并进行回流,以便为添加/填充操作腾出空间。
这是代码的粗略草图。
transition
let counter = 3;
let toasterEl = document.getElementById("toaster");
const newToast = () => toasterEl.insertAdjacentHTML('beforeend',`<div class="toast">${++counter}</div>`);
const removeToast = () => toasterEl.removeChild(toasterEl.childNodes[toasterEl.childNodes.length - 1])
#toaster {
position: fixed;
left: 0;
bottom: 0;
flex-direction: column;
max-width: 100px;
min-height: 100px;
}
.toast {
transform-origin: center bottom;
transition: ??? .5s linear;
animation: toast-entry .5s ease-in;
background-color: tan;
color: black;
padding: 10px;
margin: 10px;
width: 100%;
text-align: center;
}
@keyframes toast-entry {
0% {
transform: rotateX(90deg);
opacity: 0.5;
}
50% {
transform: rotateX(0deg);
opacity: 1;
}
}
答案 0 :(得分:1)
没有简单的方法可以单独使用CSS来完成此操作,因为auto
-dimensions cannot be animated。这意味着您需要先了解自己的尺寸,也可以像libraries such as materialize do这样快速计算尺寸。
也许是这样的:
https://codepen.io/anon/pen/ydjPMj
<button onclick="newToast()">Make toast</button>
<button onclick="removeToast()">Burn toast</button>
<div id="toaster">
<div class="toast">1</div>
<div class="toast">2</div>
<div class="toast">3</div>
</div>
#toaster {
position: fixed;
left: 0;
bottom: 0;
height: 100px;
max-width: 100px;
transition: height 2s;
}
.toast {
background-color: tan;
color: black;
padding: 10px;
margin: 10px;
width: 100%;
height: 1em;
text-align: center;
}
let counter = 3;
let toasterEl = document.getElementById("toaster");
toasterEl.style.height = "9em";
const newToast = () => {
toasterEl.insertAdjacentHTML(
"beforeend",
`<div class="toast">${++counter}</div>`
);
toasterEl.style.height = parseInt(toasterEl.style.height) + 3 + "em";
};
const removeToast = () => {
toasterEl.removeChild(toasterEl.childNodes[toasterEl.childNodes.length - 1]);
toasterEl.style.height = parseInt(toasterEl.style.height) - 3 + "em";
}
[编辑] ,您可能还想look into flex-grow
,但这并不是您想要的,但是如果您对解决方案的几何知识有所了解,则可以帮助您破解解决方案每个吐司内部的DOM。
答案 1 :(得分:1)
我想说,达到预期效果的最佳方法是在过渡完成后监听这些元素上的transitionend
事件和.remove()
该元素。
这是一个有效的示例:
let counter = 3;
let toasterEl = document.getElementById("toaster");
const newToast = () => toasterEl.insertAdjacentHTML('beforeend',`<div class="toast">${++counter}</div>`);
const removeToast = () => {
var child = toasterEl.childNodes[ toasterEl.childNodes.length - 1 ];
child.style.height = child.offsetHeight + 'px';
child.addEventListener( 'transitionend', function( e ) {
this.remove();
});
// this is a trick to let browser paint set `offsetHeight` first then start transition from that value to zero
setTimeout( function() {
child.style.height = child.style.paddingTop = child.style.paddingBottom = child.style.marginTop = child.style.marginBottom = 0;
}, 10 );
}
#toaster {
position: fixed;
left: 0;
bottom: 0;
flex-direction: column;
max-width: 200px;
min-height: 200px;
}
.toast {
transform-origin: center top;
overflow: hidden;
transition: height .3s ease-out, margin .3s ease-out, padding .3s ease-out;
animation: toast-entry .5s ease-in;
background-color: tan;
color: black;
padding: 20px;
margin: 10px;
width: 100%;
box-sizing: border-box;
text-align: center;
}
@keyframes toast-entry {
0% {
transform: rotateX(90deg);
opacity: 0.5;
}
50% {
transform: rotateX(0deg);
opacity: 1;
}
}
<button onclick="newToast()">Make toast</button>
<button onclick="removeToast()">Burn toast</button>
<div id="toaster">
<div class="toast">1</div>
<div class="toast">2</div>
<div class="toast">3</div>
</div>
值得一提:
transition
和padding
属性以及margin
本身上使用height
。box-sizing
更改为border-box
。transitionend
的其他带前缀事件的名称。e.propertyName
属性。答案 2 :(得分:0)
您正在立即从DOM中删除该元素,因此将不应用任何过渡或动画。您可以在要删除元素时添加一个类(带有动画),并在完成过渡一段时间后,删除该元素。
let counter = 3;
let toasterEl = document.getElementById("toaster");
const newToast = () => toasterEl.insertAdjacentHTML('beforeend',`<div class="toast">${++counter}</div>`);
const removeToast = () => {
toasterEl.childNodes[toasterEl.childNodes.length - 1].classList.add("remove")
setTimeout(()=>{
toasterEl.removeChild(toasterEl.childNodes[toasterEl.childNodes.length - 1])
},200)
}
#toaster {
position: fixed;
left: 0;
bottom: 0;
flex-direction: column;
max-width: 100px;
min-height: 100px;
}
.toast {
transform-origin: center bottom;
transition: all .5s linear;
animation: toast-entry .5s ease-in;
background-color: tan;
color: black;
padding: 10px;
margin: 10px;
width: 100%;
text-align: center;
}
.remove{
transform:scaleY(0);
opacity: 0;
}
@keyframes toast-entry {
0% {
transform: rotateX(90deg);
opacity: 0.5;
}
50% {
transform: rotateX(0deg);
opacity: 1;
}
}
<button onclick="newToast()">Make toast</button>
<button onclick="removeToast()">Burn toast</button>
<div id="toaster">
<div class="toast">1</div>
<div class="toast">2</div>
<div class="toast">3</div>
</div>
希望这会有所帮助!