1. 程式人生 > >CSS3 不執行 Transition 過渡動畫

CSS3 不執行 Transition 過渡動畫

如果元素設定了transition,那麼當 JavaScript 改變相應屬性值的時候,就會觸發該過渡動畫。

有時候,我們想直接設定該值,而不觸發過渡動畫,最直觀的想法就是先設定 transition-duration 為0,然後設定該值,最後恢復 transition 的值。但是這個方法是行不通的,因為JavaScript是單執行緒的,它採用訊息機制,當我們給元素賦予某個樣式的時候,它並沒有立即執行,而是繼續處理當前的訊息佇列,直到進入到某個專門處理CSS的階段(RecalculateStyle)。**這點和Node.js的事件機制很像。**前面說到JavaScript是單執行緒,因此採用上面方法的結果是“對同一個屬性賦值,後面的覆蓋前面的”,因此後續觸發RecalculateStyle的時候,依然會觸發過渡動畫。

因此,解決該問題的思路就有兩種

  • 修改訊息的先後順序。
    通過人為的設定一個延遲(setTimeout、requestAnimationFrame),使transition的設定在RecalculateStyle之後被處理
  • 手動觸發 RecalculateStyle 使得修改生效。
    注意到有個 getComputedStyle 方法用來獲取計算後的樣式(以前我常用在獲取偽元素的樣式上),既然要計算樣式,那麼必定會觸發 RecalculateStyle,這樣之前的CSS就被處理了。

測試程式碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<style>
body {
	display: flex;
}
div {
	width: 15em;
	height: 10em;
	border: 1px solid black;
	margin: 1em;
	display: flex;
	justify-content: center;
	align-items: center;
}
</style>
<script>
//js中是沒有node.js的process.nextTick和window.setImmediate這兩個方法的
window.onload = ()=> {
	const [div1, div2, div3, div4, div5] = document.getElementsByTagName("div");
	
	div1.style.backgroundColor = "red";
	div1.style.transition = "background-color 5s";
	
	div2.style.backgroundColor = "red";
	window.setTimeout(()=>{
		div2.style.transition = "background-color 5s";
	}, 100);
	
	div3.style.backgroundColor = "red";
	
	const start = new Date().getTime();
	window.requestAnimationFrame(()=>{
		const end = new Date().getTime();
		const cost = end-start;
		console.log(cost); //我這裡是只花了18ms
		div3.style.transition = "background-color 5s";
	});

	div4.style.color = "yellow";
	div4.style.backgroundColor = "red";
	div4.style.marginLeft = "4em";
	//獲取的並不一定要是transition中設定的屬性,通常隨便獲取一個屬性都會導致RecalculateStyle(animation、transition等少部分屬性不在其中)
	getComputedStyle(div4).length;
	//這段一定要放在獲取只讀的計算屬性之後
	div4.style.transition = "all 5s";

}
</script>
</head>
<body>
<div>原始</div><div>setTimeout</div><div>requestAnimationFrame</div><div>getComputedStyle</div>
</body>
</html>