玩 JavaScript 和 CSS 过渡,我试图删除一个 CSS 类在动态插入div之后,使用JavaScript和innerHTML。
我真的很惊讶地看到与蓝色div的不透明度相关的CSS过渡没有按照我想要的方式触发(在Safari下工作,在Chrome下随机工作,在Firefox Dev Edition下不起作用)。有人可以解释这种现象吗?
我不确定为什么它的工作方式与红色div 的工作方式不同。也许我不知道浏览器如何处理内部HTML?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Having fun with JS</title>
<style>
.std {
width:100px;
height:100px;
opacity: 1;
transition: opacity 5s;
}
.std--hidden {
opacity: 0;
}
.std--red {
background-color: red;
}
.std--blue {
background-color: blue;
}
</style>
</head>
<body>
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>
<script>
// let a chance to the browser to trigger a rendering event before the class is toggled
// see http://stackoverflow.com/a/4575011
setTimeout(function() {
// everything works fine for the red div
document.querySelector('.std--red').classList.toggle('std--hidden');
}, 0);
document.querySelector('button').addEventListener('click', function(e) {
var template = `<div class='std std--blue std--hidden'></div>`;
document.querySelector('.insert-here').innerHTML = template;
setTimeout(function() {
// Why does the CSS transition seems to be triggered randomly ?
// well more exactly
// - it works under my Safari
// - it does not work under my FirefoxDeveloperEdition
// - it works randomly under my Google Chrome
document.querySelector('.std--blue').classList.toggle('std--hidden');
}, 0);
});
</script>
</body>
</html>
编辑
所以我刚刚阅读了 CSS 过渡规范并发现了这个
对一组同时进行的样式更改的这种处理称为 样式更改事件。(实现通常具有样式更改 事件,以对应于他们所需的屏幕刷新率,以及何时 脚本需要最新的计算样式或布局信息 依赖于它的 API。
这可以以某种方式解释吗?setTimeout 0 在某些浏览器上是否太快,以至于它们没有时间计算样式差异,因此不会触发样式更改事件?事实上,如果使用更长的 setTimeout(例如,~16.6666,猜测 1/60 刷新率......),它似乎在任何地方都有效。有人可以确认吗?
我想我已经找到了答案,请参阅 CSS 3 过渡规范:
由于此规范未定义样式更改事件的时间 发生,因此考虑对计算值的更改 同时,作者应该意识到,更改任何 进行更改后一小段时间的转换属性 这种转变可能会导致行为在 实现,因为更改可能被视为同时在 一些实现,但不是其他实现。
我试图添加一点延迟,让浏览器注意到样式差异,并且它始终如一地工作。似乎某些浏览器执行 setTimeout 0 的速度确实比其他浏览器快:-)
setTimeout(function() {
document.querySelector('.std--blue').classList.toggle('std--hidden');
}, 17);
要触发转换,您实际上不需要类来切换。这很重要,因为您可能无法动态设置类以事先切换。换句话说,您可能只需要更改一些CSS属性来触发转换。不过是的...您需要满足以下条件;
- 为了使
<div id="blue"></div>
元素进行动画处理,它必须携带定义transition
的std
类。所以首先我们应该像blue.classList.add("std");
- 您需要异步执行任务。异步刷新 DOM 最好由
requestAnimationFrame()
函数完成。
var blue = document.getElementById("blue");
blue.classList.add("std");
blue.style.backgroundColor = "blue";
blue.style.opacity = 0;
document.querySelector('button')
.addEventListener( 'click'
, _ => requestAnimationFrame(_ => blue.style.opacity = 1)
);
.std { width:100px;
height:100px;
opacity: 1;
transition: opacity 5s;
}
.std--red { background-color: red;}
<button>click here</button>
<div class='std std--red'></div>
<div id="blue"></div>
似乎您必须通过引用样式来触发过渡。我只是简单地添加了这一行(甚至添加到控制台.log也可以)
document.querySelector('.std.std--blue').style.width = '20';
在这里它的工作原理:JSFIDDLE
注意:我正在使用FirefoxDeveloperEdition。
我遵循了以下解决方案:
添加或删除类时,CSS 过渡不会进行动画处理,只会在更改 CSS 属性时进行动画处理。
完整脚本
<script>
setTimeout(function() {
// everything works fine for the red div
document.querySelector('.std--red').classList.toggle('std--hidden');
}, 0);
document.querySelector('button').addEventListener('click', function(e) {
var template = `<div class='std std--blue std--hidden'></div>`;
document.querySelector('.insert-here').innerHTML = template;
document.querySelector('.std.std--blue').style.width = '20';
setTimeout(function() {
document.querySelector('.std.std--blue').style.width = '100';
document.querySelector('.std--blue').classList.toggle('std--hidden');
}, 0);
});
</script>
超时设置一个值,以便为元素插入 DOM 留出时间(在调用 document.querySelector
之前必须存在)
setTimeout(function() { document.querySelector('.std--blue').classList.toggle('std--hidden')},100);
您不需要第一次超时
onload = function() {
document.querySelector('.std--red').classList.toggle('std--hidden');
document.querySelector('button').addEventListener('click', function(e) {
var template = "<div class='std std--blue std--hidden'></div>";
document.querySelector('.insert-here').innerHTML = template;
setTimeout(function() { document.querySelector('.std--blue').classList.toggle('std--hidden')},100);
});
}
.std {
width:100px;
height:100px;
opacity: 1;
transition: opacity 5s;
}
.std--hidden {
opacity: 0;
}
.std--red {
background-color: red;
}
.std--blue {
background-color: blue;
}
<button>click here</button>
<div class='std std--red std--hidden'></div>
<div class='insert-here'>
</div>