在Chrome / Mac上强制DOM重绘/刷新

每过一段时间,Chrome都会错误地呈现完全有效的HTML / CSS或根本不呈现。 通过DOM检查器进行挖掘往往足以使其认识到其方法的错误并正确重绘,所以可以certificate标记是好的。 在我正在进行的一个项目中,这种情况经常(而且是可以预测的)发生了,我已经把代码放在了某些地方强制重绘的地步。

这适用于大多数浏览器/操作系统组合:

el.style.cssText += ';-webkit-transform:rotateZ(0deg)' el.offsetHeight el.style.cssText += ';-webkit-transform:none' 

如在,调整一些未使用的CSS属性,然后要求一些信息,强制重绘,然后解开财产。 不幸的是,Mac版Chrome浏览器后面的团队似乎已经find了一种方法,可以在不重绘的情况下获得offsetHeight。 从而杀死其他有用的黑客。

到目前为止,为了在Chrome / Mac上获得同样的效果,最好的办法就是这样的丑陋:

  $(el).css("border", "solid 1px transparent"); setTimeout(function() { $(el).css("border", "solid 0px transparent"); }, 1000); 

在其中,实际上迫使元素跳了一下,然后冷却了一秒钟,然后跳回去。 更糟糕的是,如果你把这个超时减less到500ms以下,那么它往往不会达到预期的效果,因为浏览器在它回到原始状态之前不会重新绘制。

有人愿意提供一个更好的版本,这个刷新/刷新黑客(最好基于上面的第一个例子)在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 } 

编辑:为了回应ŠimeVidas我们在这里实现的将是一个强制回stream。 你可以从大师本人了解更多http://paulirish.com/2011/dom-html5-css3-performance/

上面的答案都没有为我工作。 我注意到, 调整我的窗口确实导致重绘。 所以这对我来说是这样的:

 $(window).trigger('resize'); 

这个解决scheme没有超时! 真正的力量重绘! 适用于Android和iOS。

 var forceRedraw = function(element){ var disp = element.style.display; element.style.display = 'none'; var trick = element.offsetHeight; element.style.display = disp; }; 

我们最近遇到了这个问题,发现用translateZ将这个受影响的元素提升到一个复合层 ,而不需要额外的javascript。

 .willnotrender { transform: translateZ(0); } 

由于这些绘画问题主要在Webkit / Blink中出现,而且此修补程序主要针对Webkit / Blink,所以在某些情况下更可取。 特别是因为许多JavaScript解决scheme导致回stream和重绘 ,而不仅仅是重绘。

这对我有用。 荣誉去这里 。

 jQuery.fn.redraw = function() { return this.hide(0, function() { $(this).show(); }); }; $(el).redraw(); 

隐藏一个元素,然后在setTimeout 0中再次显示它将强制重绘。

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

这似乎为我做了诡计。 另外,它真的不显示。

 $(el).css("opacity", .99); setTimeout(function(){ $(el).css("opacity", 1); },20); 

调用window.getComputedStyle()应该强制重排

如果你想保存在你的样式表中声明的样式,最好使用如下的东西:

 jQuery.fn.redraw = function() { this.css('display', 'none'); var temp = this[0].offsetHeight; this.css('display', ''); temp = this[0].offsetHeight; }; $('.layer-to-repaint').redraw(); 

注意:使用最新的webkit / blink,必须存储offsetHeight的值才能触发重绘,否则VM(为了优化目的)可能会跳过该指令。

更新:增加了第二个offsetHeight阅读,有必要防止浏览器排队/caching下列CSS属性/类更改与display值的恢复(这样一个CSS转换,可以遵循应呈现)

我今天在OSX El Capitan用Chrome v51遇到了这个挑战。 有问题的页面在Safari中运行良好。 我尝试了几乎所有的build议 – 没有任何工作正确 – 都有副作用…我最终实现了下面的代码 – 超级简单 – 没有任何副作用(仍然像以前一样在Safari中)。

解决scheme:根据需要在有问题的元素上切换一个类。 每个切换将强制重绘。 (为了方便起见,我使用了jQuery,但是香草JavaScript应该没有问题…)

jQuery类切换

 $('.slide.force').toggleClass('force-redraw'); 

CSS类

 .force-redraw::before { content: "" } 

就是这样

注:您必须运行下面的“整页”片段才能看到效果。

 $(window).resize(function() { $('.slide.force').toggleClass('force-redraw'); }); 
 .force-redraw::before { content: ""; } html, body { height: 100%; width: 100%; overflow: hidden; } .slide-container { width: 100%; height: 100%; overflow-x: scroll; overflow-y: hidden; white-space: nowrap; padding-left: 10%; padding-right: 5%; } .slide { position: relative; display: inline-block; height: 30%; border: 1px solid green; } .slide-sizer { height: 160%; pointer-events: none; //border: 1px solid red; } .slide-contents { position: absolute; top: 10%; left: 10%; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p> This sample code is a simple style-based solution to maintain aspect ratio of an element based on a dynamic height. As you increase and decrease the window height, the elements should follow and the width should follow in turn to maintain the aspect ratio. You will notice that in Chrome on OSX (at least), the "Not Forced" element does not maintain a proper ratio. </p> <div class="slide-container"> <div class="slide"> <img class="slide-sizer" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"> <div class="slide-contents"> Not Forced </div> </div> <div class="slide force"> <img class="slide-sizer" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"> <div class="slide-contents"> Forced </div> </div> </div> 

示例Html:

 <section id="parent"> <article class="child"></article> <article class="child"></article> </section> 

JS:

  jQuery.fn.redraw = function() { return this.hide(0,function() {$(this).show(100);}); // hide immediately and show with 100ms duration }; 

通话function:

$('article.child').redraw(); // <坏主意

 $('#parent').redraw(); 
 function resizeWindow(){    var evt = document.createEvent('UIEvents');    evt.initUIEvent('resize', true, false,window,0);    window.dispatchEvent(evt); } 

在500毫秒后调用此函数。

一个方法,我在IE上工作(我不能使用显示技术,因为有一个input,不能放松焦点)

它有效,如果你有0的余量(改变填充工程以及)

 if(div.style.marginLeft == '0px'){ div.style.marginLeft = ''; div.style.marginRight = '0px'; } else { div.style.marginLeft = '0px'; div.style.marginRight = ''; } 

仅限CSS。 这适用于删除或添加子元素的情况。 在这些情况下,边界和圆angular会留下伪影。

 el:after { content: " "; } el:before { content: " "; } 

我修复了IE10 + IE11。 基本上会发生的是,你必须在重新计算的包装元素中添加一个DIV。 然后把它删除,瞧吧 奇迹般有效 :)

  _initForceBrowserRepaint: function() { $('#wrapper').append('<div style="width=100%" id="dummydiv"></div>'); $('#dummydiv').width(function() { return $(this).width() - 1; }).width(function() { return $(this).width() + 1; }); $('#dummydiv').remove(); }, 

大多数答案都需要使用asynchronous超时,这会导致恼人的眨眼。

但我想出了这个,因为它是同步的,所以工作顺利:

 var p = el.parentNode, s = el.nextSibling; p.removeChild(el); p.insertBefore(el, s); 

这是我的解决scheme,消失的内容…

 <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> 

我碰到类似的问题,这个简单的JS帮助解决了这个问题:

 document.getElementsByTagName('body')[0].focus(); 

在我的情况下,这是一个Chrome扩展的错误,而不是在扩展中改变其CSS后重画页面。