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

2020/10/14 07:41 · javascript ·  · 0评论

Chrome有时会不正确地显示或完全不显示完全有效的HTML / CSS。通过DOM检查器进行挖掘通常足以使它意识到其方式的错误并正确重绘,因此,可以证明标记是好的。在我正在研究的项目中,这种情况经常发生(并且可以预测)到足以在某些情况下强制执行重绘的代码位置。

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

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

如图所示,调整一些未使用的CSS属性,然后要求一些信息以强制重绘,然后取消调整该属性。不幸的是,Mac版Chrome背后的聪明团队似乎找到了一种无需重新绘制即可获取offsetHeight的方法。从而杀死本来有用的黑客。

到目前为止,我想出的在Chrome / Mac上获得相同效果的最好方法是:

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

在这种情况下,实际上是迫使该元素稍微跳一下,然后冷却一秒钟再跳回来。更糟糕的是,如果将超时时间降低到500ms以下(不太明显),则通常不会达到预期的效果,因为浏览器在返回原始状态之前无法进行重绘。

有人愿意提供适用于Chrome / Mac的此重绘/刷新hack(最好基于上述第一个示例)的更好版本吗?

不确定您要实现的目标,但这是我过去成功使用的一种方法,可以成功地强制浏览器重绘,也许对您有用。

// 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的回应,我们在这里实现的结果是强制性回流。您可以从大师本人身上找到更多信息http://paulirish.com/2011/dom-html5-css3-performance/

上面的答案对我都不起作用。我确实注意到调整窗口大小确实会导致重画。因此,这为我做到了:

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

我们最近遇到了这一问题,并发现使用translateZ将受影响的元素提升为复合层可以解决此问题,而无需使用额外的javascript。

.willnotrender { 
   transform: translateZ(0); 
}

由于这些绘画问题主要出现在Webkit / Blink中,并且此修复程序主要针对Webkit / Blink,因此在某些情况下更可取。特别是因为许多JavaScript的解决方案事业回流和重绘,而不仅仅是一个重绘。

这个解决方案没有超时!重绘!适用于Android和iOS。

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

这对我有用。荣誉来到这里

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()应强制重排

今天,我在带有Chrome v51的OSX El Capitan中遇到了这个挑战。有问题的页面在Safari中运行良好。我尝试了此页面上的几乎所有建议-没有一个可行的方法-所有这些都有副作用...我最终实现了以下代码-超级简单-没有副作用(仍然像以前在Safari中一样起作用)。

解决方案:根据需要在有问题的元素上切换类。每个切换将强制重画。(为了方便起见,我使用了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>
function resizeWindow(){
    var evt = document.createEvent('UIEvents');
    evt.initUIEvent('resize'truefalse,window,0);
    window.dispatchEvent(evt); 
}

500毫秒后调用此函数。

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

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读,有必要防止浏览器随着display的恢复而在随后的CSS属性/类更改中排队/缓存(通过这种方式,应该呈现可以跟随的CSS转换)

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

    };

调用函数:

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

$('#parent').redraw();

2020年:更轻更强大

以前的解决方案对我不再有用。

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

该解决方案使浏览器绘制一个克隆来替换原始元素。它有效并且可能更具可持续性:

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

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

在IE上对我有用的一种方法(我不能使用显示技术,因为有输入不能放宽焦点)

如果您的边距为0,则可以使用(更改填充也可以)

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

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

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();
    },

大多数答案都需要使用异步超时,这会引起烦人的眨眼。

但是我想出了这个,它可以同步工作,因此很顺利:

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

这是我用于消失内容的解决方案...

<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后,Chrome扩展程序未重绘页面。

我想将所有状态返回到先前状态(无需重新加载),包括由jquery添加的元素。上面的实现将行不通。我做了如下。

// Set initial HTML description
var defaultHTML;
function DefaultSave() {
  defaultHTML = document.body.innerHTML;
}
// Restore HTML description to initial state
function HTMLRestore() {
  document.body.innerHTML = defaultHTML;
}



DefaultSave()
<input type="button" value="Restore" onclick="HTMLRestore()">

我有一个React组件列表,当滚动该组件时,然后打开另一个页面,然后返回时,直到滚动页面后,该列表才在Safari iOS上呈现。所以这就是解决方法。

    componentDidMount() {
        setTimeout(() => {
            window.scrollBy(0, 0);
        }, 300);
    }

下面的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;
}

它帮助了我

domNodeToRerender.style.opacity = 0.99;
setTimeout(() => { domNodeToRerender.style.opacity = '' }, 0);

2020年10月,Chrome 85仍然存在问题。

morewry使用transform的解决方案:translateZ(0)实际上可以进行任何转换,包括translate(0,0)和scale(1),但是如果必须再次更新该元素,则诀窍是切换转换,并且最好的方法是在一帧后使用requestAnimationFrame直接将其删除(应始终避免使用setTimeout,因为它会变慢,因此会引起故障)。

因此,更新一个元素:

    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');
        });
    }
本文地址:http://javascript.askforanswer.com/zaichrome-macshangqiangzhidomzhonghui-shuaxin.html
文章标签: ,   ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!