Chrome / Mac에서 DOM 다시 그리기 / 새로 고침


215

때때로 Chrome은 완전히 유효한 HTML / CSS를 잘못 렌더링하거나 전혀 렌더링하지 않습니다. DOM 인스펙터를 파는 것만으로도 길을 잘못 인식하고 올바르게 다시 그리기에 충분하기 때문에 마크 업이 좋은 경우 일 수 있습니다. 이것은 특정 상황에서 다시 그리기를 강제하기 위해 코드를 배치 한 작업중 인 프로젝트에서 자주 (그리고 예측 가능하게) 충분히 발생합니다.

이것은 대부분의 브라우저 / OS 조합에서 작동합니다 :

    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에서 작동하는이 다시 그리기 / 새로 고침 해킹 (위의 첫 번째 예를 기반으로 함)의 더 나은 버전을 제공하려고합니까?


몇 분 전에 같은 문제가 발생했습니다. div의 요소를 변경하면 (스팬) 브라우저가 변경 사항을 올바르게 다시 작성합니다. 나는 이것이 조금 오래되었다는 것을 알고 있지만 이것은 내가 생각하는 일부 형제를 도울 수 있습니다.
Andrés Torres

2
불투명도 0.99와 관련하여 아래의 답변을 참조하십시오. 여기서 가장 좋은 답변이지만 페이지의 깊이가 너무 쉽기 때문에 쉽게 찾을 수 없습니다.
Grouchal

1
이것은 리눅스에서도 발생합니다 :-(
schlingel

1
타임 아웃을 requestAnimationFrame으로 대체 할 수 있습니다.이 경우 동일한 것을 달성하지만 1000ms 대신 16ms의 지연 시간을 갖습니다.
trusktr

3
잘못된 렌더링에 대해 Chromium 문제제기 하십시오 . 4 년 전 이었지만 아무도 그렇게하지 않은 것으로 보입니다.
Bardi Harborow

답변:


183

정확히 무엇을 달성하려고하는지 확실하지 않지만 이것은 브라우저에서 다시 그리기를 강제하기 위해 과거에 사용했던 방법입니다. 아마도 당신에게 도움이 될 것입니다.

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

편집 : Šime Vidas에 대한 응답으로 우리가 여기서 달성하는 것은 강제 리플 로우입니다. 마스터 자신에게서 더 많은 것을 찾을 수 있습니다 http://paulirish.com/2011/dom-html5-css3-performance/


3
Afaik, 뷰포트의 일부만 다시 그릴 수는 없습니다. 브라우저는 항상 전체 웹 페이지를 다시 그립니다.
Šime Vidas

38
$ ( '# parentOfElementToBeRedrawn'). hide (). show () 대신에; Chrome에서 제대로 작동하려면 .hide.show (0)가 필요했습니다
l.poellabauer

1
@ l.poellabauer 여기 동일합니다-이것은 말이되지 않습니다 ...하지만 감사합니다. 도대체 어떻게 알았습니까 ??? :)
JohnIdol

6
참고로, 내가 작업하고 있던 관련 영역은 무한 스크롤 목록이었습니다. 내가 주위를 재생하고 당신이 경우에 것을 발견, 그래서 전체 UL를 표시 / 숨기기에 약간 쓸모이었다 .hide().show(0)어떤 요소 (I 페이지 바닥 글을 선택)는 페이지를 새로 고침해야한다.
treeface

1
뷰포트의 일부만 다시 그릴 수 있습니다. 그렇게하는 API는 없지만 브라우저는 그렇게 할 수 있습니다. 뷰포트는 타일로 색칠되어 시작됩니다. 그리고 복합 층은 독립적으로 페인트됩니다.
morewry

62

위의 답변 중 어느 것도 나를 위해 일하지 않았습니다. 창 크기조정 하면 다시 그리기가 발생 했음을 알았습니다 . 그래서 이것은 나를 위해 그것을했습니다 :

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

11
힌트 :이 영업 이익이 원하는하지 무엇을 아마 많은 비용과 성능이다 완전한 창, 다시 그린다
hereandnow78

7
창 크기를 조정하면 항상 리플 로우가 트리거되지만 코드 $(window).trigger('resize')는 그렇지 않으며 관련 처리기가 할당 된 경우 'resize'이벤트 만 발생합니다.
guari

1
일주일 내내 구해줘! 내 문제는 <body style = "zoom : 67 %">을 설정 한 후 페이지가 예상 수준으로 확대되었지만 페이지가 고정되어 스크롤 할 수 없다는 것입니다. 귀하의 답변으로이 문제를 즉시 해결했습니다
user1143669

30

최근에이 문제가 발생 하여 translateZ 를 사용하여 영향을받는 요소를 컴포지트 레이어 로 승격하면 추가 자바 스크립트가 없어도 문제가 해결 되는 것으로 나타났습니다 .

.willnotrender { 
   transform: translateZ(0); 
}

이러한 페인팅 문제는 주로 Webkit / Blink에 표시되며이 수정은 대부분 Webkit / Blink를 대상으로하기 때문에 경우에 따라 선호됩니다. 특히 많은 JavaScript 솔루션이 리 페인팅 뿐만 아니라 리플 로우 및 리 페인트를 유발하기 때문 입니다.


1
캔버스가 지속적으로 애니메이션이 되더라도 문제가 캔버스에 그려진 HTML 요소가 제거되었을 때 문제가 없었습니다.
Knaģ은

이로 인해 레이아웃 문제가 해결되었습니다 neon-animated-pages. 감사합니다 : +1 :
coffeesaga

1
이것은 효과가 있었다. Safari는 div 세트에 표시되지 않고 표시 할 수 없으며 선택할 수없는 요소를 남겼습니다. 창 크기를 조정하면 사라졌습니다. 이 변환을 추가하면 "아티팩트"가 예상대로 사라졌습니다.
Jeff Mattson

28

타임 아웃이없는이 솔루션! 진짜 힘을 다시 그리기! Android 및 iOS 용

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

1
Chrome에서는 작동하지 않으며 Linux에서는 FF가 작동하지 않습니다. 그러나 단순히 (디스플레이 속성을 수정하지 않고) element.offsetHeight에 접근 하지 작업. 요소가 보이지 않으면 브라우저가 offsetHeight 계산을 건너 뜁니다.
Grodriguez

이 솔루션은 "overwolf"에 사용 된 크롬 기반 브라우저에서 발생한 버그를 해결하는 데 완벽하게 작동합니다. 나는 이것을하는 방법을 알아 내려고 노력했고 노력을 구했다.
nacitar sevaht

13

이것은 나를 위해 작동합니다. Kudos는 여기에 간다 .

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

$(el).redraw();

1
그러나 때로는 페이지 구조를 파괴 할 수있는 '디스플레이 : 블록'과 같은 '유지'를 남겼습니다.
pie6k

이것은 본질적으로 동일해야합니다$().hide().show(0)
Mahn

@Mahn 시도 했습니까? 내 생각에 .hide ()는 비 블로킹이므로 브라우저의 다시 렌더링 실행을 일명 방법의 요점으로 건너 뛸 것입니다. (그리고 내가 올바르게 기억한다면, 그때 다시 테스트했습니다.)
zupa

2
@zupa은 시험이고 크롬 38 일 트릭 즉 show()다른 show(0)후자의 기간을 지정하여, 바로 시간을 제공하는이 같은 방식으로 렌더링하는 대신하는 타임 아웃에 jQuery를 애니메이션 방법에 의해 트리거하다는 사실에 hide(0, function() { $(this).show(); })않습니다 .
Mahn

@Mahn 좋아, 그럼 잘 잡아. 크로스 플랫폼에서 작동하고 최근 jQuery 기능이 아닌 경우 귀하의 솔루션을위한 것입니다. 테스트 할 시간이 없으므로 '작동 할 수 있습니다'로 추가하겠습니다. 위의 사항에 해당한다고 생각되면 답변을 편집 할 수 있습니다.
zupa

9

요소를 숨기고 setTimeout 0 내에 다시 표시하면 다시 그리기가 수행됩니다.

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

1
이것은 SVG 필터가 때때로 다시 페인트하지 않는 크롬 버그, bugs.chromium.org/p/chromium/issues/detail?id=231560 에서 작동했습니다 . 타임 아웃이 중요했습니다.
Jason D

이것은 Chrome에서 강제로 값을 다시 계산하도록 시도하는 동안 나를 위해 일한 myElement.getBoundingClientRect()것으로 최적화 / 성능 목적으로 캐시되었습니다. DOM에 새 요소를 추가하고 이전 (캐시 된) 값이있는 이전 요소가 DOM에서 제거 된 후 새 값을 가져 오는 함수에 0 밀리 초의 시간 제한을 추가했습니다.
TheDarkIn1978

6

이것은 나를 위해 속임수를 쓰는 것 같습니다. 또한 실제로 전혀 표시되지 않습니다.

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

이 버그와 관련하여 Chromium 버전 60.0.3112.113에서 문제가 발생했습니다 . 문제 727076 . 효율적이고 미묘한; 많은 감사합니다.
Lonnie Best

@ wiktus239 아마도 20 밀리 초가 너무 빠르며 브라우저가 1.0으로 다시 변경하기 전에 .99로 변경할 시간이 없습니까? —이 불투명도 트릭은 어쨌든 iOS의 콘텐츠를 iPhone iOS 12 Safari에서 볼 수있게 만들고 1 000 밀리 초마다 토글합니다. 그것은 또한 위의 의견 (1000 밀리미터)의 링크 된 문제 727076에있는 것입니다.
KajMagnus

4

window.getComputedStyle()리플 로우


2
나를 위해 작동하지 않았지만 아마도 offsetHeightCSS가 아닌 속성이 필요하기 때문일 수 있습니다.
Sebas

3

오늘 Chrome v51을 사용하는 OSX El Capitan에서이 문제에 부딪 쳤습니다. 해당 페이지는 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>


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

500 밀리 초 후에이 함수를 호출하십시오.


2

스타일 시트에 선언 된 스타일을 유지하려면 다음과 같은 것을 사용하는 것이 좋습니다.

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 : 최신 웹킷 / 블링크에서는 offsetHeight다시 그리기를 트리거하기 위해 값을 저장해야합니다 . 그렇지 않으면 VM (최적화 목적으로)이 해당 명령을 생략합니다.

업데이트 : 두 번째 offsetHeight독서를 추가 했으므로 display값을 복원하여 브라우저가 다음 CSS 속성 / 클래스 변경을 대기열에 넣거나 캐싱하지 못하게해야 합니다 (이렇게하면 CSS 전환이 렌더링되어야 함)


1

샘플 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();

요소 .fadeIn(1)대신에 .show(300)요소를 밀지 않고 나를 대신하여 작동합니다 . 그래서 나는 그것이 display:none다시 시작 되고 다시 시작된다고 생각 합니다block
BananaAcid

0

IE에서 나를 위해 일한 접근법 (포커스를 느슨하게해서는 안되는 입력이 있었기 때문에 디스플레이 기술을 사용할 수 없었습니다)

여백이 0 인 경우 작동합니다 (패딩도 변경)

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

0

CSS 만. 자식 요소가 제거되거나 추가되는 상황에서 작동합니다. 이러한 상황에서 테두리와 둥근 모서리는 인공물을 남길 수 있습니다.

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

0

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

대부분의 답변에는 비동기 시간 초과를 사용해야하므로 성가신 깜박임이 발생합니다.

그러나 나는 이것을 동기식이기 때문에 부드럽게 작동합니다.

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

이러한 요소에 연결된 이벤트가 계속 작동합니까?
케리 존슨

0

이것은 사라지는 내용에 효과가있는 내 솔루션입니다 ...

<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

비슷한 문제가 발생 하여이 간단한 JS 줄이 문제를 해결하는 데 도움이되었습니다.

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

내 경우에는 확장 프로그램 내에서 CSS를 변경 한 후 Chrome 확장 프로그램이 페이지를 다시 그리지 않는 버그였습니다.


4
이것은 키보드 접근성을 손상시킵니다.
Pangamma 2016 년

0

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

스크롤 할 때 반응 형 구성 요소 목록이 있었고 다른 페이지를 연 다음 다시 돌아올 때 페이지가 스크롤 될 때까지 Safari iOS에서 목록이 렌더링되지 않았습니다. 이것이 수정입니다.

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

0

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

그것은 나를 도왔다

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

0

2020 년 : 가볍고 강함

이전 솔루션은 더 이상 작동하지 않습니다.

브라우저는 점점 더 "무의미한"변화를 감지하여 그리기 프로세스를 최적화한다고 생각합니다.

이 솔루션은 브라우저가 원본 요소를 대체하기 위해 복제본을 그립니다. 작동하고 아마도 더 지속 가능합니다.

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

Chrome 80 / Edge 80 / Firefox 75에서 테스트되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.