IT story

WebKit이 스타일 변경을 전파하기 위해 다시 그리거나 다시 그리도록하려면 어떻게해야합니까?

hot-time 2020. 4. 8. 08:01
반응형

WebKit이 스타일 변경을 전파하기 위해 다시 그리거나 다시 그리도록하려면 어떻게해야합니까?


스타일 변경에 영향을주는 간단한 JavaScript가 있습니다.

sel = document.getElementById('my_id');
sel.className = sel.className.replace(/item-[1-9]-selected/,'item-1-selected');
return false;

이것은 최신 버전의 FF, Opera 및 IE에서는 잘 작동하지만 최신 버전의 Chrome 및 Safari에서는 실패합니다.

형제 자매 인 두 자손에게 영향을 미칩니다. 첫 번째 형제는 업데이트되지만 두 번째 형제는 업데이트되지 않습니다. 두 번째 요소의 자식도 포커스를 가지며 onclick 속성 에 위의 코드가 포함 된 <a> 태그를 포함 합니다.

크롬 "개발자 도구"창에서 나는 (예를 들어, 선택 해제 및 검사) 슬쩍 찌르다 경우 어떤 의 속성 모든 요소가 올바른 스타일의 두 번째 형제 업데이트를.

WebKit을 올바른 프로그래밍 방식으로 쉽고 프로그래밍 방식으로 "nudge"하는 해결 방법이 있습니까?


나는 복잡한 제안과 작동하지 않는 많은 간단한 제안을 찾았지만 Vasil Dinkov 의 의견 중 하나 는 다시 그리기 / 다시 그리기를 강제로 수행하는 간단한 솔루션을 제공했습니다.

sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='';

“block”이 아닌 다른 스타일에 효과가 있다면 다른 사람이 댓글을 달도록하겠습니다.

고마워, 바실!


최근에이 문제가 발생하여 CSS에서 translateZ 를 사용하여 영향을받는 요소를 복합 레이어승격하면 추가 JavaScript 없이도 문제가 해결되는 것으로 나타났습니다.

.willnotrender { 
   transform: translateZ(0); 
}

이러한 페인팅 문제는 주로 Webkit / Blink에 표시되며이 수정은 대부분 Webkit / Blink를 대상으로하기 때문에 경우에 따라 선호됩니다. 허용 대답은 거의 확실 원인이 특히 이후 리플 로우 및 다시 그리기 , 하지 만 다시 그리기를.

Webkit과 Blink는 렌더링 성능을 위해 열심히 노력해 왔으며 이러한 종류의 결함은 불필요한 흐름과 페인트를 줄이는 것을 목표로 한 최적화의 부작용입니다. CSS가 변경 되거나 다른 사양이 향후 솔루션이 될 것입니다.

복합 레이어를 달성하는 다른 방법이 있지만 이것이 가장 일반적입니다.


danorton 솔루션이 효과가 없었습니다. 웹킷이 일부 요소를 전혀 그리지 않는 이상한 문제가있었습니다. 입력의 텍스트는 onblur까지 업데이트되지 않았습니다. className을 변경해도 다시 그려지지 않습니다.

내가 우연히 발견 한 내 솔루션은 스크립트 뒤에 빈 스타일 요소를 본문에 추가하는 것이 었습니다.

<body>
...
<script>doSomethingThatWebkitWillMessUp();</script>
<style></style>
...

그것은 그것을 고쳤다. 얼마나 이상합니까? 이것이 누군가에게 도움이되기를 바랍니다.


디스플레이 + 오프셋 트리거가 작동하지 않으므로 여기에서 해결책을 찾았습니다.

http://mir.aculo.us/2009/09/25/force-redraw-dom-technique-for-webkit-based-browsers/

element.style.webkitTransform = 'scale(1)';

나는 같은 문제를 겪고 있었다. danorton의 'toggling display'수정이 애니메이션의 단계 기능에 추가되었을 때 저에게 효과적이지만 성능에 대해 걱정하고 다른 옵션을 찾았습니다.

내 상황에서 다시 칠하지 않은 요소는 당시 z- 색인이없는 절대 위치 요소 내에있었습니다. 이 요소에 z- 색인을 추가하면 Chrome의 동작이 변경되고 예상대로 애니메이션이 부드럽게 다시 그려집니다.

이것이 만병 통치약인지 의심합니다 .Chrome이 요소를 다시 그리지 않기로 선택한 이유에 달려 있다고 생각합니다. 그러나이 특정 솔루션을 누군가를 돕기 위해 여기에 게시하고 있습니다.

건배, 롭

tl; dr >> 요소 또는 그 부모에 z- 색인을 추가하십시오.


다음과 같이 작동합니다. 순수 CSS에서는 한 번만 설정하면됩니다. 그리고 그것은 JS 함수보다 더 안정적으로 작동합니다. 성능에는 영향을 미치지 않습니다.

@-webkit-keyframes androidBugfix {from { padding: 0; } to { padding: 0; }}
body { -webkit-animation: androidBugfix infinite 1s; }

어떤 이유로 나는 danorton의 대답을 얻을 수 없었지만, 그것이해야 할 것을 알 수 있었으므로 이것을 조금 조정했습니다.

$('#foo').css('display', 'none').height();
$('#foo').css('display', 'block');

그리고 그것은 나를 위해 일했습니다.


나는 오늘 이것을 우연히 발견했다 : prototype.js에 대한 Element.redraw ()

사용 :

Element.addMethods({
  redraw: function(element){
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    (function(){n.parentNode.removeChild(n)}).defer();
    return element;
  }
});

그러나 문제가있는 요소에서 redraw ()를 직접 호출 해야하는 경우가 있습니다. 때로는 부모 요소를 다시 그리더라도 아이가 겪고있는 문제가 해결되지 않습니다.

브라우저가 요소를 렌더링하는 방법에 대한 좋은 기사 : 렌더링 : 다시 그리기, 리플 로우 / 릴레이 아웃, 스타일 변경


CSS를 변경 한 후 Chrome에서 스크롤 막대를 다시 그려야하기 때문에 여기에 왔습니다.

누군가 같은 문제가 발생하면이 함수를 호출하여 문제를 해결했습니다.

//Hack to force scroll redraw
function scrollReDraw() {
    $('body').css('overflow', 'hidden').height();
    $('body').css('overflow', 'auto');
}

이 방법은 최선의 해결 방법은 아니지만 다시 작성해야하는 요소를 숨기거나 표시하면 모든 문제를 해결할 수 있습니다.

여기 내가 사용한 바이올린이 있습니다 : http://jsfiddle.net/promatik/wZwJz/18/


와 함께 다른 div에 삽입 된 많은 div 에이 문제가 있었고 삽입 position: absolute된 div에는 위치 속성이 없었습니다. 내가 이것을 바꿨을 때 position:relative잘 작동했습니다. (문제를 정확히 지적하기가 어려웠습니다)

필자의 경우 Angular로 삽입 된 요소는입니다 ng-repeat.


나는 이것이 2014 년에도 여전히 문제가 있다고 믿을 수 없다. 나는 스크롤하는 동안 페이지의 왼쪽 하단에 고정 위치 캡션 상자를 새로 고칠 때이 문제가 있었는데, 캡션은 화면 위로 올라 간다. 위의 모든 것을 성공하지 않고 시도한 후 DOM 릴레이 아웃이 매우 짧아서 다소 부 자연스러운 느낌의 스크롤링 등으로 인해 많은 문제가 느리고 원인이 있음을 알았습니다.

나는 고정 된 위치, 풀 사이즈 div를 작성 pointer-events: none하고 그 요소에 danorton의 대답을 적용하여 DOM을 방해하지 않고 전체 화면에서 다시 그리기를 강제하는 것처럼 보입니다.

HTML :

<div id="redraw-fix"></div>

CSS :

div#redraw-fix {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 25;
    pointer-events: none;
    display: block;
}

JS :

sel = document.getElementById('redraw-fix');
sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='block';

이 질문에 다른 대답이 필요하지는 않지만 특정 상황에서 단일 비트로 색상을 변경하면 강제로 다시 페인트 할 수 있습니다.

//Assuming black is the starting color, we tweak it by a single bit
elem.style.color = '#000001';

//Change back to black
setTimeout(function() {
    elem.style.color = '#000000';
}, 0);

setTimeout현재 이벤트 루프 밖에서 두 번째 스타일의 변화를 이동하는 것이 중요 입증했다.


나를 위해 유일한 해결책은 sowasred2012의 답변과 비슷합니다.

$('body').css('display', 'table').height();
$('body').css('display', 'block');

페이지에 많은 문제 블록이 있으므로 display루트 요소의 속성을 변경 합니다. 스크롤 오프셋을 재설정 하기 때문에 display: table;대신에을 사용 합니다 .display: none;none


모든 사람이 자신의 문제와 해결책을 가지고있는 것 같아서, 나에게 맞는 것을 추가 할 것이라고 생각했습니다. 현재 Chrome이있는 Android 4.1에서 overflow : hidden으로 div 내부에서 캔버스를 드래그하려고하면 부모 div에 요소를 추가하지 않으면 다시 그릴 수 없었습니다 (해를 끼치 지 않을 것입니다).

var parelt = document.getElementById("parentid");
var remElt = document.getElementById("removeMe");
var addElt = document.createElement("div");
addElt.innerHTML = " "; // Won't work if empty
addElt.id="removeMe";
if (remElt) {
    parelt.replaceChild(addElt, remElt);
} else {
    parelt.appendChild(addElt);
}

화면 깜박임이나 실제 업데이트가 없으며 나 자신을 청소하십시오. 전역 또는 클래스 범위 변수가 없으며 지역 변수 만 있습니다. Mobile Safari / iPad 또는 데스크탑 브라우저에서 아무것도 아프지 않은 것 같습니다.


absoluteIOS 장치 (iPhone 4,5,6, 6+)에서 위 또는 아래로 스크롤 할 때 요소를 배치 한 몇 가지 화면에서 이온 html5 앱을 작업 중입니다 .iPhone 버그를 다시 칠했습니다.

많은 해결책을 시도했지만이 문제가 내 문제를 해결하는 것 외에는 아무것도 작동하지 않았습니다.

.fixRepaint절대 위치 요소에 CSS 클래스 사용했습니다.

.fixRepaint{
    transform: translateZ(0);
}

이것은 내 문제를 해결했으며 일부 도움이 될 수 있습니다.


transform: translateZ(0);방법을 사용 하지만 경우에 따라 충분하지 않습니다.

나는 클래스를 추가하고 제거하는 팬이 아니므로 이것을 해결하는 방법을 찾으려고 노력한 새로운 해킹으로 끝났습니다.

@keyframes redraw{
    0% {opacity: 1;}
    100% {opacity: .99;}
}

// ios redraw fix
animation: redraw 1s linear infinite;

이것은 JS에 좋습니다

sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='block';

그러나 Jquery에서, 특히 $ (document) .ready 만 사용할 수 있고 특정 이유로 객체의 .load 이벤트에 바인딩 할 수없는 경우 다음이 작동합니다.

객체 / div의 OUTER (MOST) 컨테이너를 가져 와서 모든 내용을 변수로 제거한 다음 다시 추가해야합니다. 외부 컨테이너 내에서 수행 된 모든 변경 사항이 표시됩니다.

$(document).ready(function(){
    applyStyling(object);
    var node = $("div#body div.centerContainer form div.centerHorizontal").parent().parent();
    var content = node.html();
    node.html("");
    node.html(content);
}

전환으로 작업 할 때이 방법이 유용하다는 것을 알았습니다.

$element[0].style.display = 'table'; 
$element[0].offsetWidth; // force reflow
$element.one($.support.transition.end, function () { 
    $element[0].style.display = 'block'; 
});

내 경우에는 적어도 "애니메이션 / 요소에 적용 할 때"display / offsetHeight "핵이 작동하지 않았습니다.

페이지 내용을 열고 닫는 드롭 다운 메뉴가있었습니다. 아티팩트는 메뉴가 닫힌 후 페이지 컨텐츠에 남아있었습니다 (웹킷 브라우저에서만). "display / offsetHeight"핵이 작동 한 유일한 방법은 내가 그것을 몸에 적용하는 것입니다.

그러나 다른 해결책을 찾았습니다.

  1. 요소가 애니메이션을 시작하기 전에 "-webkit-backface-visibility : hidden;"을 정의하는 클래스를 추가하십시오. 요소에 (인라인 스타일을 사용할 수도 있습니다.)
  2. 애니메이션이 끝나면 클래스 또는 스타일을 제거하십시오.

이것은 여전히 ​​해킹 적이지만 (하드웨어 렌더링을 강제하기 위해 CSS3 속성을 사용합니다) 적어도 문제의 요소에만 영향을 미치며 PC 및 Mac의 Safari 및 Chrome 모두에서 저에게 효과적이었습니다.


이것은 관련이있는 것 같습니다 : jQuery 스타일Safari에 적용되지 않습니다

첫 번째 응답에서 제안 된 솔루션은 이러한 시나리오에서 나에게 효과적이었습니다. 즉 스타일을 변경 한 후 더미 클래스를 본문에 적용하고 제거하십시오.

$('body').addClass('dummyclass').removeClass('dummyclass');

이로 인해 사파리가 다시 그려집니다.


위의 제안은 저에게 효과적이지 않았습니다. 그러나 아래는 그렇습니다.

앵커 내부의 텍스트를 동적으로 변경하고 싶습니다. "검색"이라는 단어. id 속성으로 내부 태그 "font"를 작성했습니다. 자바 스크립트를 사용하여 컨텐츠 관리 (아래)

검색

스크립트 내용 :

    var searchText = "Search";
    var editSearchText = "Edit Search";
    var currentSearchText = searchText;

    function doSearch() {
        if (currentSearchText == searchText) {
            $('#pSearch').panel('close');
            currentSearchText = editSearchText;
        } else if (currentSearchText == editSearchText) {
            $('#pSearch').panel('open');
            currentSearchText = searchText;
        }
        $('#searchtxt').text(currentSearchText);
    }

특정 상황에서 방향이 변경되면 Android 용 Chrome에서 사라지는 SVG 문제가 발생했습니다. 아래 코드는 그것을 재현하지 않지만 우리가 가진 설정입니다.

body {
  font-family: tahoma, sans-serif;
  font-size: 12px;
  margin: 10px;
}
article {
  display: flex;
}
aside {
  flex: 0 1 10px;
  margin-right: 10px;
  min-width: 10px;
  position: relative;
}
svg {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
}
.backgroundStop1 {
  stop-color: #5bb79e;
}
.backgroundStop2 {
  stop-color: #ddcb3f;
}
.backgroundStop3 {
  stop-color: #cf6b19;
}
<article>
  <aside>
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="100%" width="100%">
      <defs>
        <linearGradient id="IndicatorColourPattern" x1="0" x2="0" y1="0" y2="1">
          <stop class="backgroundStop1" offset="0%"></stop>
          <stop class="backgroundStop2" offset="50%"></stop>
          <stop class="backgroundStop3" offset="100%"></stop>
        </linearGradient>
      </defs>
      <rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" fill="url(#IndicatorColourPattern)"></rect>
    </svg>
  </aside>
  <section>
    <p>Donec et eros nibh. Nullam porta, elit ut sagittis pulvinar, lacus augue lobortis mauris, sed sollicitudin elit orci non massa. Proin condimentum in nibh sed vestibulum. Donec accumsan fringilla est, porttitor vestibulum dolor ornare id. Sed elementum
      urna sollicitudin commodo ultricies. Curabitur tristique orci et ligula interdum, eu condimentum metus eleifend. Nam libero augue, pharetra at maximus in, pellentesque imperdiet orci.</p>
    <p>Fusce commodo ullamcorper ullamcorper. Etiam eget pellentesque quam, id sodales erat. Vestibulum risus magna, efficitur sed nisl et, rutrum consectetur odio. Sed at lorem non ligula consequat tempus vel nec risus.</p>
  </section>
</article>

일주일 후 파고 들고 prodding 후 여기에 제공된 해키 솔루션에 만족하지 못했지만 , 문제는 새로운 요소를 그리는 동안 요소를 메모리에 유지하는 것처럼 보였기 때문에 발생했습니다. 해결책은 SVG에서 linearGradient의 ID를 페이지 당 한 번만 사용하더라도 고유하게 만드는 것입니다.

이것은 여러 가지 방법으로 달성 될 수 있지만, 앵귤러 앱의 경우 lodash uniqueId 함수를 사용하여 변수를 범위에 추가했습니다.

각도 지시문 (JS) :

scope.indicatorColourPatternId = _.uniqueId('IndicatorColourPattern');

HTML 업데이트 :

5 행 : <linearGradient ng-attr-id="{{indicatorColourPatternId}}" x1="0" x2="0" y1="0" y2="1">

11 행 : <rect x="0" y="0" rx="5" ry="5" width="100%" height="100%" ng-attr-fill="url(#{{indicatorColourPatternId}})"/>

이 답변으로 다른 사람이 키보드를 훼손하는 일을 할 수 있기를 바랍니다.


리플 로우를 강제로 덜 해킹하고보다 공식적인 방법을 권장합니다 : forceDOMReflowJS 사용 하십시오 . 귀하의 경우 코드는 다음과 같습니다.

sel = document.getElementById('my_id');
forceReflowJS( sel );
return false;

요소에 내용 스타일을 추가하면 다시 페인트해야한다는 것을 알았으므로 다시 그리기를 원할 때마다 다른 값이어야하며 의사 요소에있을 필요가 없습니다.

.selector {
    content: '1'
}

나는 morewry 답변을 시도했지만 그것은 효과가 없습니다. 다른 브라우저와 비교할 때 Safari와 동일한 clientWidth를 사용하는 데 문제가 있었고이 코드는 문제를 해결했습니다.

var get_safe_value = function(elm,callback){
    var sty = elm.style
    sty.transform = "translateZ(1px)";
    var ret = callback(elm)//you can get here the value you want
    sty.transform = "";
    return ret
}
// for safari to have the good clientWidth
var $fBody = document.body //the element you need to fix
var clientW = get_safe_value($fBody,function(elm){return $fBody.clientWidth})

get_safe_value 이후에 clientWidth를 다시 얻으려고하면 사파리로 잘못된 값을 얻습니다. 게터 sty.transform = "translateZ(1px)";사이에 있어야하기 때문에 정말 이상합니다.sty.transform = "";

결정적으로 작동하는 다른 솔루션은

var $fBody = document.body //the element you need to fix
$fBody.style.display = 'none';
var temp = $.body.offsetHeight;
$fBody.style.display = ""
temp = $.body.offsetHeight;

var clientW = $fBody.clientWidth

문제는 포커스와 스크롤 상태를 잃는다는 것입니다.


jquery를 사용한 간단한 솔루션 :

$el.html($el.html());

또는

element.innerHTML = element.innerHTML;

html에 추가되었을 때 표시되지 않은 SVG가있었습니다.

svg 요소가 화면에 표시된 후에 추가 할 수 있습니다.

더 나은 해결책은 다음을 사용하는 것입니다.

document.createElementNS('http://www.w3.org/2000/svg', 'svg');

그리고 jQuery와 함께 :

$(svgDiv).append($(document.createElementNS('http://www.w3.org/2000/svg', 'g'));

Chrome에서 올바르게 렌더링됩니다.

참고 URL : https://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes

반응형