首页 > 解决方案 > 如果在将 div 插入 DOM 后更改其样式,为什么转换不起作用?

问题描述

代码很简单:

ground = document.getElementsByClassName('ground')[0]
item = document.createElement('div')
item.classList.add('roll')
item.style.transition = 'transform 5s linear'
item.style.transform = 'translateX(100%)';
ground.appendChild(item)
item.style.transform = 'translateX(-300px)';
.ground {
    position: absolute;
    width:500px;
    height: 500px;
    background-color: orange;
}
.roll {
    position: absolute;
    right: 0;
    width: 100px;
    height: 100px;
    background-color: red;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <div class='ground'></div>
  </body>
</html>

我希望它是一个从右到左移动的红色块,因为我改变了变换的样式,它是在“过渡”中声明的属性。但是红色块只出现在'translateX(-300px)'的位置,我认为它应该结束。

标签: htmlcssfrontend

解决方案


您的代码的问题是浏览器会看到您同时应用 CSS 转换样式(也就是在同一个调用堆栈中)。这会导致浏览器“短路”并确定它是真正重要的最终布局,并忽略translateX(100%)中间的。

为了强制转换,您需要告诉浏览器您要在调用堆栈末尾执行下一次转换。这将产生强制浏览器执行第一个转换,然后执行第二个转换的效果。

在调用堆栈末尾调用某些内容的示例是使用window.setTimeout()延迟0

const ground = document.getElementsByClassName('ground')[0];
const item = document.createElement('div');

item.classList.add('roll');
item.style.transition = 'transform 5s linear';
item.style.transform = 'translateX(100%)';
ground.appendChild(item);

// Mutate transform attribute at end of callstack
window.setTimeout(() => {
  item.style.transform = 'translateX(-300px)';
}, 0);
.ground {
  position: absolute;
  width: 500px;
  height: 500px;
  background-color: orange;
}

.roll {
  position: absolute;
  right: 0;
  width: 100px;
  height: 100px;
  background-color: red;
}
<div class='ground'></div>


如果你想要一个更现代的解决方案,你总是可以使用 async/await 机制。这将避免不必要地嵌套超时回调:

const ground = document.getElementsByClassName('ground')[0];
const item = document.createElement('div');

// Sleeper function
function sleep(duration) {
  return new Promise(resolve => window.setTimeout(resolve, duration));
}

async function animate() {
  item.classList.add('roll');
  item.style.transition = 'transform 5s linear';
  item.style.transform = 'translateX(100%)';
  ground.appendChild(item);
  
  // Sleep for 0ms (aka push operation to end of callstack)
  await sleep(0);

  // Mutate transform attribute at end of callstack
  item.style.transform = 'translateX(-300px)';
}

animate();
.ground {
  position: absolute;
  width: 500px;
  height: 500px;
  background-color: orange;
}

.roll {
  position: absolute;
  right: 0;
  width: 100px;
  height: 100px;
  background-color: red;
}
<div class='ground'></div>


推荐阅读