如何强制WebKit重绘/重绘以传播样式更改?

dan*_*ton 243 css safari webkit google-chrome

我有一些简单的JavaScript来实现样式更改:

sel = document.getElementById('my_id');
sel.className = sel.className.replace(/item-[1-9]-selected/,'item-1-selected');
return false;
Run Code Online (Sandbox Code Playgroud)

这适用于最新版本的FF,Opera和IE,但在最新版本的Chrome和Safari上失败.

它会影响两个后代,这些后代恰好是兄弟姐妹.第一个兄弟更新,但第二个没有.第二个元素的子元素也具有焦点,并包含<a>标记,该标记在onclick属性中包含上述代码.

在Chrome"开发人员工具"窗口中,如果我轻推(例如取消选中并检查)任何元素的任何属性,则第二个兄弟会更新为正确的样式.

是否有一种解决方法可以轻松地以编程方式"轻推"WebKit做正确的事情?

dan*_*ton 304

我发现了一些复杂的建议和许多简单的建议没有用,但Vasil Dinkov对其中一个的评论提供了一个简单的解决方案来强制重绘/重绘工作正常:

sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='';
Run Code Online (Sandbox Code Playgroud)

如果它适用于"阻止"以外的样式,我会让其他人评论.

谢谢,瓦西里!

  • 为避免闪烁,您可以尝试"'inline-block'","'table'"或[`'run-in'``(http://www.quirksmode.org/css/display.html#runin)而不是''没有',但这可能有副作用.此外,超时为0会触发回流,就像查询`offsetHeight`一样:`sel.style.display ='run-in'; setTimeout(function(){sel.style.display ='block';},0);` (31认同)
  • 这个答案在2年后仍然有用.我只是用它来解决仅限Chrome的问题,在以某种方式调整浏览器大小后,屏幕上仍然存在CSS框阴影.谢谢! (14认同)
  • PS:对我来说上面的解决方案不再适用了.相反,我使用了这个(jQuery):sel.hide().show(0); 资料来源:http://stackoverflow.com/questions/8840580/force-dom-redraw-refresh-on-chrome-mac (11认同)
  • 您需要做的就是读取尺寸属性,您不需要来回更改它. (7认同)
  • @danorton你在2010年回答.这是2013年,而且这个问题仍然存在.谢谢.顺便说一句,任何人都知道webkit跟踪器上是否有任何问题? (5认同)
  • 现在是2015年,这个答案仍然具有现实意义.花了我两个小时才找到.谢谢! (4认同)
  • 更改可见性可能比更改显示属性更好. (2认同)
  • 还是一个bug.读取offsetHeight本身并没有解决我的问题,更改显示属性是不切实际的,所以我使用了visibility属性,它工作了!我将以下内容放在我的jQuery.animate()回调函数中:this.style.visibility ="hidden"; this.offsetHeight; this.style.visibility ="可见"; 我需要所有3行来使它工作.动画仍然不会一直显示,但是当它完成时,它将显示在正确的位置而不是部分地显示在其他地方或根本不显示. (2认同)
  • 这解决了我的问题,即 Chrome 无法正确更新正在由 JavaScript 调整大小的块内儿童的宽度和高度。该元素使用 CSS calc 和 Viewport 单位。我用 sel.style.display='table'; sel.offsetHeight; sel.style.display='block'; (初始状态是块)。 (2认同)

mor*_*wry 89

我们最近遇到过这种情况,并发现在CSS中使用translateZ将受影响的元素提升为复合层可以解决问题而无需额外的JavaScript.

.willnotrender { 
   transform: translateZ(0); 
}
Run Code Online (Sandbox Code Playgroud)

由于这些绘画问题主要出现在Webkit/Blink中,并且此修复主要针对Webkit/Blink,因此在某些情况下更为可取.特别是因为接受的答案几乎肯定会引起回流并重新粉刷,不仅仅是重画.

Webkit和Blink一直致力于渲染性能,这些故障是优化的不幸副作用,旨在减少不必要的流量和涂料. 很可能,CSS将会改变,或者另一个成功的规范将成为未来的解决方案.

还有其他方法可以实现复合层,但这是最常见的.

  • 最初的问题是在 2010 年提出的。这个答案是在 2014 年写的,是一个很好的解决方案。现在是 2019 年,这仍然是一个问题(尽管仅在 Safari 中)......玩得好,WebKit。 (2认同)
  • safari 很糟糕,新的 ie6 (2认同)

Ger*_*ben 51

danorton解决方案对我不起作用.我有一些非常奇怪的问题,webkit根本不会绘制一些元素; 输入中的文本直到onblur才更新; 并且更改className不会导致重绘.

我意外地发现,我的解决方案是在脚本之后向主体添加一个空样式元素.

<body>
...
<script>doSomethingThatWebkitWillMessUp();</script>
<style></style>
...
Run Code Online (Sandbox Code Playgroud)

修好了.这有多奇怪?希望这对某人有帮助.

  • 这条单线对我来说很棒!'$( '<风格> </样式>')appendTo($(document.body的))除去();` (33认同)
  • 只知道这会强制重绘整个页面,而大多数时候你只想重新绘制页面的某个部分...... (11认同)
  • 刚用这个混合了Pumbaa80对另一个答案的评论.我最后得到的修复是`var div = $('<div>').appendTo(element); setTimeout(function(){div.remove();},0);` (5认同)
  • 如果可以的话,我会投票100万次.这是我可以让chrome重绘一个愚蠢的div的唯一方法.顺便说一句,你不必添加一个样式元素(至少我没有)任何元素都可以工作.我做了一个div并给了它一个id所以我可以删除然后在每一步添加元素,以便不用无用的标签填充DOM. (3认同)

Eri*_*icG 32

由于显示器+偏移触发器对我不起作用,我在这里找到了一个解决方案:

http://mir.aculo.us/2009/09/25/force-redraw-dom-technique-for-webkit-based-browsers/

element.style.webkitTransform = 'scale(1)';
Run Code Online (Sandbox Code Playgroud)

  • 我在一个正在尝试的黑客中使用过这个,但是我没有将它作为`scale.style.webkitTransform = element.style.webkitTransform`分配给它.之所以将它设置为前者,是因为"绝对定位元素"会略微扭曲页面! (3认同)

Rob*_*phy 23

我遇到了同样的问题.danorton的'切换显示'修复程序在添加到动画的步进功能时对我有效,但我关注性能而且我寻找其他选项.

在我的情况下,没有重新绘制的元素是在一个绝对的位置元素内,当时它没有z指数.在此元素中添加z-index会改变Chrome的行为并重新按照预期发生 - >动画变得平滑.

我怀疑这是灵丹妙药,我认为这取决于为什么 Chrome选择不重绘元素,但我在这个特定的解决方案中发布了它希望有人的帮助.

干杯,罗布

tl; dr >>尝试将z-index添加到元素或其父元素中.

  • 辉煌.这很棒,并为我解决了这个问题.A +++会再次z-index. (8认同)

swe*_*eds 16

以下作品.它只需要在纯CSS中设置一次.它比JS功能更可靠.表现似乎不受影响.

@-webkit-keyframes androidBugfix {from { padding: 0; } to { padding: 0; }}
body { -webkit-animation: androidBugfix infinite 1s; }
Run Code Online (Sandbox Code Playgroud)


sow*_*012 13

出于某种原因,我无法得到danorton的工作答案,我可以看到它应该做什么,所以我稍微调整了一下:

$('#foo').css('display', 'none').height();
$('#foo').css('display', 'block');
Run Code Online (Sandbox Code Playgroud)

它对我有用.

  • 我尝试过这一切,但只有这一个对我有用.WTF webkit!这不是计算机科学!这是黑魔法! (7认同)

Ant*_*ida 7

我来到这里是因为我需要在更改其CSS后重绘Chrome中的滚动条.

如果某人有同样的问题,我通过调用此函数解决了它:

//Hack to force scroll redraw
function scrollReDraw() {
    $('body').css('overflow', 'hidden').height();
    $('body').css('overflow', 'auto');
}
Run Code Online (Sandbox Code Playgroud)

这种方法不是最好的解决方案,但它可以解决所有问题,隐藏和显示需要重绘的元素可以解决所有问题.

这是我用它的小提琴:http://jsfiddle.net/promatik/wZwJz/18/


Ada*_*lin 6

我今天偶然发现了这个:Element.js的Element.redraw()

使用:

Element.addMethods({
  redraw: function(element){
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    (function(){n.parentNode.removeChild(n)}).defer();
    return element;
  }
});
Run Code Online (Sandbox Code Playgroud)

但是,有时我注意到你必须直接在有问题的元素上调用redraw().有时重绘父元素不会解决孩子遇到的问题.

关于浏览器呈现元素的方式的好文章:渲染:重绘,重排/重新布局,重新设置