每隔一段时间,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?


当前回答

如果你想保留样式表中声明的样式,最好使用如下的方法:

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转换)

其他回答

下面的css适用于我的IE 11和Edge,不需要JS。 scaleY(1)在这里起作用。这似乎是最简单的解决办法。

.box {
    max-height: 360px;
    transition: all 0.3s ease-out;
    transform: scaleY(1);
}
.box.collapse {
    max-height: 0;
}

这是我解决内容消失的方法……

<script type = 'text/javascript'>
    var trash_div;

    setInterval(function()
    {
        if (document.body)
        {
            if (!trash_div)
                trash_div = document.createElement('div');

            document.body.appendChild(trash_div);
            document.body.removeChild(trash_div);
        }
    }, 1000 / 25); //25 fps...
</script>

2020:更轻更强

以前的解决办法对我已经不管用了。

我猜浏览器通过检测越来越多的“无用”更改来优化绘图过程。

这个解决方案使浏览器绘制一个克隆来替换原来的元素。它很有效,而且可能更可持续:

const element = document.querySelector('selector');
if (element ) {
  const clone = element.cloneNode(true);
  element.replaceWith(clone);
}

在Chrome 80 / Edge 80 / Firefox 75上测试

如果你想保留样式表中声明的样式,最好使用如下的方法:

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转换)

隐藏一个元素,然后在setTimeout为0的情况下再次显示它将强制重绘。

$('#page').hide();
setTimeout(function() {
    $('#page').show();
}, 0);