每隔一段时间,Chrome会不正确地呈现完全有效的HTML/CSS或根本不呈现。深入DOM检查器通常足以让它意识到其方法的错误并正确地重新绘制,因此可以证明标记是好的。在我所从事的项目中,这种情况经常发生(并且可以预见),以至于我已经在某些情况下放置了代码来强制重绘。
这适用于大多数浏览器/操作系统组合:
el.style.cssText += ';-webkit-transform:rotateZ(0deg)'
el.offsetHeight
el.style.cssText += ';-webkit-transform:none'
例如,调整一些未使用的CSS属性,然后要求一些强制重绘的信息,然后取消调整属性。不幸的是,Chrome for Mac背后的聪明团队似乎已经找到了一种方法,可以在不重新绘制的情况下获得这种offsetHeight。这样就杀死了一个有用的黑客。
到目前为止,为了在Chrome/Mac上获得同样的效果,我想出的最好的方法是:
$(el).css("border", "solid 1px transparent");
setTimeout(function()
{
$(el).css("border", "solid 0px transparent");
}, 1000);
实际上,强制元素跳跃一点,然后冷却一秒钟,然后再跳回来。更糟糕的是,如果您将超时时间降低到500ms以下(到不太明显的地方),通常不会达到预期的效果,因为浏览器在恢复到原始状态之前不会重新绘制。
有人愿意提供一个更好的版本的重绘/刷新hack(最好基于上面的第一个例子),工作在Chrome/Mac?
不确定你到底想要达到什么目的,但这是我过去使用的一种方法,成功地迫使浏览器重新绘制,也许它对你有用。
// in jquery
$('#parentOfElementToBeRedrawn').hide().show(0);
// in plain js
document.getElementById('parentOfElementToBeRedrawn').style.display = 'none';
document.getElementById('parentOfElementToBeRedrawn').style.display = 'block';
如果这个简单的重画不工作,你可以试试这个。它在元素中插入一个空文本节点,以保证重绘。
var forceRedraw = function(element){
if (!element) { return; }
var n = document.createTextNode(' ');
var disp = element.style.display; // don't worry about previous display style
element.appendChild(n);
element.style.display = 'none';
setTimeout(function(){
element.style.display = disp;
n.parentNode.removeChild(n);
},20); // you can play with this timeout to make it as short as possible
}
编辑:在回应Šime Vidas,我们在这里实现的将是一个强制回流。你可以从大师本人http://paulirish.com/2011/dom-html5-css3-performance/找到更多信息
2020年10月,Chrome 85仍然存在该问题。
morewry的使用transform:translateZ(0)的解决方案,实际上,任何转换工作,包括translate(0,0)和scale(1),但如果你必须再次更新元素,那么技巧是切换转换,最好的方法是直接删除它,在一帧后,使用requestAnimationFrame (setTimeout应该总是避免,因为它会更慢,所以它可能会导致故障)。
updateone元素:
function refresh_element(node) {
// you can use scale(1) or translate(0, 0), etc
node.style.setProperty('transform', 'translateZ(0)');
// this will remove the property 1 frame later
requestAnimationFrame(() => {
node.style.removeProperty('transform');
});
}
如果你想保留样式表中声明的样式,最好使用如下的方法:
jQuery.fn.redraw = function() {
this.css('display', 'none');
var temp = this[0].offsetHeight;
this.css('display', '');
temp = this[0].offsetHeight;
};
$('.layer-to-repaint').redraw();
注意:使用latest webkit/blink,存储offsetHeight的值是强制的,以触发重画,否则VM(出于优化目的)可能会跳过该指令。
更新:增加了第二次offsetHeight读取,这是必要的,以防止浏览器排队/缓存下面的CSS属性/类的变化与显示值的恢复(这样可以呈现CSS转换)