it-swarm.com.de

Erzwinge das erneute Zeichnen / Aktualisieren von DOM auf Chrome / Mac

Von Zeit zu Zeit wird Chrome) tadellos gültiges HTML/CSS falsch oder gar nicht wiedergeben. Das Durchsuchen des DOM-Inspektors reicht oft aus, um den Fehler seiner Art zu erkennen und neu zu zeichnen Richtig, also ist es nachweislich der Fall, dass das Markup gut ist. Dies passiert häufig (und vorhersehbar) genug in einem Projekt, an dem ich arbeite, dass ich Code eingerichtet habe, um unter bestimmten Umständen ein Neuzeichnen zu erzwingen.

Dies funktioniert in den meisten Browser/OS-Kombinationen:

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

Wie in Tweak einige nicht verwendete CSS-Eigenschaft, dann fragen Sie nach Informationen, die ein erneutes Zeichnen erzwingen, und deaktivieren Sie die Eigenschaft. Leider scheint das kluge Team hinter Chrome für den Mac einen Weg gefunden zu haben, diese Offset-Höhe zu erreichen, ohne sie neu zu zeichnen. Somit ist ein ansonsten nützlicher Hack erledigt.

Das Beste, was ich bisher für Chrome/Mac gefunden habe, ist diese Hässlichkeit:

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

Zwingen Sie das Element tatsächlich dazu, ein wenig zu springen, lassen Sie es dann eine Sekunde lang kalt und springen Sie es zurück. Erschwerend kommt hinzu, dass ein Timeout unter 500 ms (wo es weniger auffällt) oft nicht den gewünschten Effekt hat, da der Browser nicht zum erneuten Zeichnen kommt, bevor er in seinen ursprünglichen Zustand zurückkehrt.

Möchte jemand eine bessere Version dieses Redraw/Refresh-Hacks anbieten (vorzugsweise basierend auf dem ersten Beispiel oben), der auf Chrome/Mac funktioniert?

206
Jason Kester

Ich bin nicht sicher, was genau Sie erreichen möchten, aber dies ist eine Methode, die ich in der Vergangenheit mit Erfolg angewendet habe, um den Browser zum Neuzeichnen zu zwingen. Vielleicht funktioniert sie für Sie.

// in jquery
$('#parentOfElementToBeRedrawn').hide().show(0);

// in plain js
document.getElementById('parentOfElementToBeRedrawn').style.display = 'none';
document.getElementById('parentOfElementToBeRedrawn').style.display = 'block';

Wenn diese einfache Neuzeichnung nicht funktioniert, können Sie diese ausprobieren. Es fügt einen leeren Textknoten in das Element ein, was ein erneutes Zeichnen garantiert.

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
}

EDIT: Als Antwort auf Šime Vidas würden wir hier einen erzwungenen Reflow erreichen. Sie können mehr vom Meister selbst herausfinden http://paulirish.com/2011/dom-html5-css3-performance/

174
Juank

Keine der obigen Antworten hat bei mir funktioniert. Ich habe bemerkt, dass Größenänderung mein Fenster ein Neuzeichnen verursacht hat. Das hat es für mich getan:

$(window).trigger('resize');
61
Vincent Sels

Diese Lösung ohne Timeouts! Real Kraft neu zeichnen! Für Android und iOS.

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

Wir sind kürzlich auf dieses Problem gestoßen und haben festgestellt, dass das Heraufstufen des betroffenen Elements zu einer zusammengesetzten Ebene mit translateZ das Problem behoben hat, ohne dass zusätzliches Javascript erforderlich war.

.willnotrender { 
   transform: translateZ(0); 
}

Da diese Probleme beim Malen hauptsächlich in Webkit/Blink auftreten und sich diese Korrektur hauptsächlich auf Webkit/Blink bezieht, ist sie in einigen Fällen vorzuziehen. Zumal viele JavaScript-Lösungen ein Reflow und ein Repaint verursachen, nicht nur ein Repaint.

23
morewry

Das funktioniert bei mir. Kudos gehen hier .

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

$(el).redraw();
13
zupa

Das Ausblenden eines Elements und das erneute Anzeigen innerhalb eines setTimeout von 0 erzwingen ein erneutes Zeichnen.

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

call window.getComputedStyle() sollte einen Reflow erzwingen

4
qlqllu

Dies scheint den Trick für mich zu tun. Außerdem wird es überhaupt nicht angezeigt.

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

Ich bin heute in OSX El Capitan mit Chrome v51 auf diese Herausforderung gestoßen. Die fragliche Seite hat in Safari einwandfrei funktioniert. Ich habe fast jeden Vorschlag auf dieser Seite ausprobiert - keiner hat richtig funktioniert - alle hatten Nebenwirkungen ... Ich habe den folgenden Code implementiert - supereinfach - keine Nebenwirkungen (funktioniert immer noch wie zuvor in Safari).

Lösung: Schalten Sie eine Klasse für das problematische Element nach Bedarf um. Jedes Umschalten erzwingt ein Neuzeichnen. (Ich habe aus Bequemlichkeit jQuery verwendet, aber Vanilla JavaScript sollte kein Problem sein ...)

jQuery Class Toggle

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

CSS-Klasse

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

Und das ist es...

HINWEIS: Sie müssen das Snippet unterhalb von "Ganze Seite" ausführen, um den Effekt zu sehen.

$(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>
3
Ben Feely

Wenn Sie die in Ihren Stylesheets deklarierten Stile beibehalten möchten, sollten Sie Folgendes verwenden:

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

$('.layer-to-repaint').redraw();

NB: Mit dem neuesten Webkit/Blink muss der Wert von offsetHeight gespeichert werden, um das Repaint auszulösen. Andernfalls überspringt VM (für Optimierungszwecke) wahrscheinlich diese Anweisung .

Update: Beim zweiten Lesen von offsetHeight muss verhindert werden, dass der Browser bei der Wiederherstellung des Werts display (auf diese Weise ein CSS-Übergang) eine folgende Änderung der CSS-Eigenschaft/-Klasse in die Warteschlange stellt/zwischenspeichert das kann folgen sollte gerendert werden)

2
guari
function resizeWindow(){
    var evt = document.createEvent('UIEvents');
    evt.initUIEvent('resize', true, false,window,0);
    window.dispatchEvent(evt); 
}

rufen Sie diese Funktion nach 500 Millisekunden auf.

2
Shobhit

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

    };

Funktion aufrufen:

$('article.child').redraw(); // <== schlechte Idee

$('#parent').redraw();
1
Mehdi Rostami

Bei den meisten Antworten muss eine asynchrone Zeitüberschreitung verwendet werden, die zu einem nervigen Blinzeln führt.

Aber ich habe mir dieses ausgedacht, das reibungslos funktioniert, weil es synchron ist:

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

Das folgende CSS funktioniert für mich mit IE 11 und Edge, kein JS erforderlich. scaleY(1) erledigt hier den Trick. Scheint die einfachste Lösung zu sein.

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

Ich bin auf ein ähnliches Problem gestoßen und diese einfache Zeile von JS hat geholfen, es zu beheben:

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

In meinem Fall handelte es sich um einen Fehler mit der Erweiterung Chrome), der die Seite nicht neu zeichnet, nachdem das CSS in der Erweiterung geändert wurde.

0
Rotareti

Ich wollte alle Zustände auf den vorherigen Zustand zurücksetzen (ohne neu zu laden), einschließlich der von jquery hinzugefügten Elemente. Die obige Implementierung wird nicht funktionieren. und ich tat wie folgt.

// 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()">
0

Nur CSS. Dies funktioniert in Situationen, in denen ein untergeordnetes Element entfernt oder hinzugefügt wird. In diesen Situationen können Ränder und abgerundete Ecken Artefakte hinterlassen.

el:after { content: " "; }
el:before { content: " "; }
0
rm.rf.etc

Ein Ansatz, der für mich funktioniert hat IE (Ich konnte die Anzeigetechnik nicht verwenden, da es eine Eingabe gab, die den Fokus nicht verlieren darf)

Es funktioniert, wenn Sie einen Rand von 0 haben (das Ändern der Polsterung funktioniert auch)

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

Dies ist meine Lösung, die zum Verschwinden von Inhalten beigetragen hat ...

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

Ich hatte eine Liste der Reaktionskomponenten, die beim Scrollen eine andere Seite öffnete und beim Zurückkehren auf Safari iOS erst dann gerendert wurde, wenn die Seite gescrollt wurde. Das ist also die Lösung.

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

Mein Fix für IE10 + IE11. Grundsätzlich passiert, dass Sie einen DIV in ein Wrapping-Element einfügen, das neu berechnet werden muss. Dann entfernen Sie es einfach und voila; klappt wunderbar :)

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