web-dev-qa-db-ja.com

Chrome / MacでDOMの再描画/更新を強制する

時々、Chromeは完全に有効なHTML/CSSを不正確にまたはまったくレンダリングしません。 DOMインスペクタを使って調べてみると、そのやり方の誤りを正しく認識して正しく再描画するのに十分な場合が多いため、マークアップが適切であることは間違いありません。私が取り組んでいるプロジェクトでは、これはかなり頻繁に(そして予想通りに)発生します。特定の状況で再描画を強制するためにコードを配置しました。

これは、ほとんどのブラウザとOSの組み合わせで機能します。

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

のように、未使用のCSSプロパティをいくつか微調整してから、再描画を強制する情報を要求してから、そのプロパティを無効にします。残念ながら、Chrome for the Macの背後にある明るいチームは、再描画せずにoffsetHeightを取得する方法を見つけたようです。このように、そうでなければ便利なハックを殺します。

これまでのところ、Chrome/Macで同じ効果を得るために私が思いついたのは、この醜さです。

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

のように、実際に要素を少しジャンプさせ、次に1秒間冷やしてから元に戻します。さらに悪いことに、そのタイムアウトを500ms以下(目立たなくなるまで)に落とすと、ブラウザが元の状態に戻る前に再描画しないため、望ましい効果が得られないことがよくあります。

Chrome/Mac上で動作するこの再描画/リフレッシュハックのより良いバージョン(できれば上の最初の例に基づいて)を提供してもいいですか?

200
Jason Kester

あなたが何を達成しようとしているのか正確には分かりませんが、これは私が過去にブラウザを強制的に再描画させるために成功した方法です。

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

173
Juank

上記の答えのどれも私のために働きませんでした。私は私のウィンドウのサイズ変更が再描画を引き起こしたことに気づきました。だからこれは私のためにそれをやった:

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

タイムアウトなしでこの解決策!実数が再描画されます。 AndroidとiOSの場合.

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

私たちは最近これに遭遇し、影響を受ける要素を translateZコンポジットレイヤー にプロモートすると余分なjavascriptを必要とせずに問題が解決することを発見しました。

.willnotrender { 
   transform: translateZ(0); 
}

これらの描画の問題は主にWebkit/Blinkで発生し、この修正は主にWebkit/Blinkを対象としているので、場合によってはそれが望ましいです。特に多くのJavaScriptソリューションは、単なる再描画ではなく、 リフローおよび再描画 を引き起こすためです。

23
morewry

これは私のために働きます。 賞賛はここに行きます

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

$(el).redraw();
12
zupa

要素を非表示にしてから0のsetTimeout内で再度表示すると、強制的に再描画されます。

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

window.getComputedStyle()を呼び出すと強制的にリフローさせる

4
qlqllu

これは私のためにトリックをしているようです。さらに、それは実際にはまったく表示されません。

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

私はChrome v51を使ってOSX El Capitanで今日この課題に遭遇しました。問題のページはSafariではうまくいきました。私はこのページでほとんどすべての提案を試みました - どれも正しく機能しませんでした - すべて副作用を持っていました...私は以下のコードを実装することになりました.

解決策:必要に応じて問題のある要素のクラスを切り替えます。各トグルは再描画を強制します。 (私は便宜上jQueryを使用しましたが、Vanilla 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>
3
Ben Feely

スタイルシートに宣言されているスタイルを保持したい場合は、次のようにしてください。

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:最新のwebkit/blinkでは、再描画を引き起こすためにoffsetHeightの値を保存することは必須です。そうでなければVM(最適化の目的で)はおそらくその命令をスキップします。

更新:2回目のoffsetHeight読み取りを追加しました。ブラウザがdisplay値の復元に伴う次のCSSプロパティ/クラスの変更をキューに入れたりキャッシュしたりするのを防ぐ必要があります。

2
guari

サンプル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();
1
Mehdi Rostami

ほとんどの回答では、非同期のタイムアウトを使用する必要があり、これが煩わしい点滅を引き起こします。

しかし、私はこれを考え出しました。それは同期しているのでスムーズに動作します。

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

以下の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;
}
0
Edmond Wang
function resizeWindow(){
    var evt = document.createEvent('UIEvents');
    evt.initUIEvent('resize', true, false,window,0);
    window.dispatchEvent(evt); 
}

500ミリ秒後にこの関数を呼び出します。

0
Shobhit

私は同様の問題に遭遇しました、そして、JSのこの単純な行はそれを修理するのを助けました:

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

私の場合は、ChromeエクステンションがCSSをエクステンション内から変更した後にページを再描画しないというバグでした。

0
Rotareti

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

CSSのみこれは、子要素が削除または追加された状況で機能します。このような状況では、境界と角の丸い部分がアーティファクトを残す可能性があります。

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

IEでうまくいったアプローチ(フォーカスを緩めてはいけない入力があったので、私は表示テクニックを使うことができませんでした)

余白が0であれば動作します(パディングの変更も同様に動作します)。

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

これは私の解決策であり、コンテンツが消えるのに役立ちました...

<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

スクロールしたときに別のページを開いた後、戻ったときにページがスクロールされるまでリストがSafari iOSに表示されない反応コンポーネントリストがありました。だからこれは修正です。

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

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