programing

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

codeshow 2023. 7. 31. 22:01
반응형

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

스타일을 변경할 수 있는 몇 가지 사소한 자바스크립트가 있습니다.

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

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

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

Chrome "Developer Tools" 창에서 요소의 속성을 입력(예: 선택 취소 및 확인)하면 두 번째 형제가 올바른 스타일로 업데이트됩니다.

쉽고 프로그래밍적으로 "버깅"할 수 있는 해결 방법이 있습니까?웹킷을 통해 올바른 일을 할 수 있습니까?

저는 몇 가지 복잡한 제안들과 효과가 없는 많은 간단한 제안들을 찾았지만, 바실 딩코프가 그 중 하나에 대한 논평은 잘 작동하는 다시 그리기/다시 칠하기 위한 간단한 해결책을 제공했습니다.

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

"블록"이 아닌 다른 스타일에 사용할 수 있으면 다른 사람이 댓글을 달도록 하겠습니다.

고마워, 바실!

우리는 최근에 이것을 접했고 CSS에서 translateZ가 있는 복합 레이어로 영향을 받는 요소를 승격하면 추가 JavaScript가 필요하지 않고 문제가 해결된다는 것을 발견했습니다.

.willnotrender { 
   transform: translateZ(0); 
}

이러한 페인팅 문제는 주로 Webkit/Blink에서 나타나고, 이 픽스는 대부분 Webkit/Blink를 대상으로 하기 때문에 경우에 따라 선호됩니다.특히 수용된 답변은 단순한 재도장이 아니라 거의 확실하게 리플로우와 재도장을 유발하기 때문입니다.

Webkit와 Blink는 렌더링 성능에 많은 노력을 기울여 왔으며 이러한 결함은 불필요한 흐름과 페인트를 줄이는 것을 목표로 하는 최적화의 유감스러운 부작용입니다.CSS will-change 또는 다른 후속 사양이 미래의 해결책이 될 것입니다.

복합 레이어를 구현하는 다른 방법도 있지만 이 방법이 가장 일반적입니다.

댄도튼의 해결책은 저에게 효과가 없었습니다.웹킷이 일부 요소를 전혀 그릴 수 없는 정말 이상한 문제가 있었습니다. 입력의 텍스트가 온블러까지 업데이트되지 않았고, 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의 '토글링 디스플레이' 수정은 제 애니메이션의 스텝 기능에 추가되었을 때 저에게 효과가 있었지만, 성능에 대해 걱정하고 다른 옵션을 찾았습니다.

제 상황에서 재도색하지 않은 요소는 당시 z-index를 가지지 않은 절대 위치 요소 안에 있었습니다.이 요소에 z-index를 추가하면 Chrome의 동작이 변경되고 재도장이 예상대로 발생 -> 애니메이션이 원활해졌습니다.

저는 이것이 만병통치약인지 의심스럽습니다. 크롬이 요소를 다시 그리지 않기로 선택한 이유에 달려있다고 생각합니다. 하지만 저는 누군가를 희망하기 위해 이 구체적인 해결책을 여기에 게시합니다.

건배, 롭

tl;dr >> 요소 또는 요소의 부모에 z-index를 추가해 보십시오.

다음과 같은 작업이 가능합니다.순수 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');

그리고 그것은 저에게 효과가 있었습니다.

CSS를 변경한 후 크롬에서 스크롤바를 다시 그려야 해서 올라왔습니다.

다른 사용자가 동일한 문제를 겪고 있는 경우 다음 기능을 호출하여 해결했습니다.

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

이 방법은 최선의 해결책은 아니지만 모든 것과 함께 작동할 수 있으며, 다시 그려야 하는 요소를 숨기고 보여주면 모든 문제가 해결될 수 있습니다.

제가 사용한 바이올린은 다음과 같습니다. http://jsfiddle.net/promatik/wZwJz/18/

저는 오늘 이것을 우연히 발견했습니다.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()를 직접 호출해야 하는 경우가 종종 있습니다.때때로 부모 요소를 다시 그리면 아이가 겪고 있는 문제가 해결되지 않을 수 있습니다.

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

나는 다른 디브에 삽입된 여러 디브에 이 문제가 있었습니다.position: absolute삽입된 div에 위치 속성이 없습니다. 이걸로바꿨때을때▁this을로 바꿨을 때.position:relative그것은 잘 작동했습니다.(문제를 정확히 파악하기가 정말 어려웠습니다.)

나의 경우 앵글에 의해 삽입된 요소들은ng-repeat.

저는 이것이 2014년에도 여전히 문제라는 것을 믿을 수 없습니다.화면을 스크롤하는 동안 페이지 왼쪽 아래에 있는 고정 위치 캡션 상자를 새로 고칠 때 캡션이 화면 위로 '유령'으로 이동하는 문제가 발생했습니다.위의 모든 작업을 성공적으로 수행하지 못한 후, 매우 짧은 DOM 레이아웃을 생성하는 등으로 인해 문제가 발생하거나 약간 부자연스러운 느낌의 스크롤 등이 발생한다는 것을 알게 되었습니다.

나는 결국 고정된 위치, 풀 사이즈 디브를 만들었습니다.pointer-events: noneDOM을 방해하지 않고 전체 화면에 다시 그리기를 강요하는 것처럼 보이는 요소에 Danorton의 답변을 적용합니다.

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';

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

저는 클래스를 추가하고 제거하는 것을 좋아하지 않기 때문에 이 문제를 해결할 방법을 찾으려고 노력했지만 잘 작동하는 새로운 해킹을 하게 되었습니다.

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

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

이 질문에 다른 답이 필요한 것은 아니지만, 저는 단순히 색깔을 한 번만 바꾸는 것이 제 특정 상황에서 다시 칠하도록 강요한다는 것을 발견했습니다.

//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두 번째 스타일 변경을 현재 이벤트 루프 외부로 이동하는 데 중요한 것으로 입증되었습니다.

저에게 맞는 유일한 솔루션은 Red2012의 답변과 유사합니다.

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

페이지에 문제 블록이 많아서 변경합니다.display루트 요소의 속성입니다.그리고 나는 사용합니다.display: table;display: none;, 냐면왜none스크롤 오프셋을 재설정합니다.

모든 사람들이 각자의 문제와 해결책을 가지고 있는 것처럼 보이기 때문에, 저는 저에게 맞는 것을 추가하려고 생각했습니다.현재 Chrome이 설치된 Android 4.1에서 오버플로가 있는 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 또는 데스크톱 브라우저에서는 아무런 문제가 없는 것 같습니다.

앱을 , 몇 에는 저는이 html5앱있습다니몇, 의개화서에면온고만들을▁i▁screens,▁i▁have▁html서▁few저화55에면▁on▁on는▁ionic,▁app몇.absolute위치 요소, IOS 장치(iPhone 4, 5, 6, 6+)에서 위로 또는 아래로 스크롤할 때 재도장 버그가 발생했습니다.

많은 해결책을 시도했지만 이 해결책을 제외하고는 아무도 작동하지 않았습니다.

나는 class 는나수 css 을사습다니용했업을 해 본 적이 ..fixRepaint 요소들 에 그 절 위 있 요 소 들 에 는 에 치 대 적 인 ▁on 들 에 ▁positions 요 소 ▁those ▁elements

.fixRepaint{
    transform: translateZ(0);
}

이것이 제 문제를 해결했습니다. 누군가를 돕는 것일 수 있습니다.

이 대답은 Angular 10을 사용하는 @danorton의 솔루션에 어려움을 겪고 있는 사람들을 위한 것입니다.이 솔루션

sel.style.display='none';
sel.offsetHeight;
sel.style.display='';

에 대해서만 작동합니다."buildOptimizer": falseangular.json파일입니다 옵티마이저가 이걸 어떻게든 깨뜨린 것 같군요

이것은 JS에게 좋습니다.

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

하지만 Jquery에서, 특히 $(문서)만 사용할 수 있는 경우.준비되어 있으며 특정 이유로 개체의 .load 이벤트에 바인딩할 수 없습니다. 다음과 같은 작업이 가능합니다.

objects/divs의 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'; 
});

"디스플레이/디스플레이"높이" 해킹은 제 경우에는 작동하지 않았습니다. 적어도 애니메이션이 되는 요소에 적용되었을 때는요.

페이지 내용 위에 열려 있거나 닫혀 있는 드롭다운 메뉴가 있었습니다.아티팩트는 메뉴가 닫힌 후 페이지 내용에 남아 있습니다(웹킷 브라우저에서만)."표시/표시"하는 유일한 방법키" 해킹은 몸에 적용하면 효과가 있었는데, 이는 심술궂게 보입니다.

하지만, 저는 다른 해결책을 찾았습니다.

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

이것은 여전히 꽤 구식이지만(하드웨어 렌더링을 강제하기 위해 CSS3 속성을 사용함) 적어도 문제의 요소에만 영향을 미치며 PC와 Mac에서 사파리와 크롬 모두에서 작동했습니다.

이와 관련된 것으로 보입니다: 사파리에서 jQuery 스타일이 적용되지 않습니다.

첫 번째 응답에서 제안된 솔루션은 다음과 같은 시나리오에서 잘 작동했습니다. 즉, 스타일링을 변경한 후 인체 모형 클래스를 차체에 적용하고 제거하는 것입니다.

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

이렇게 하면 사파리가 강제로 다시 그려집니다.

위의 제안들은 저에게 효과가 없었습니다. 하지만 아래의 것들은 효과가 있습니다.

앵커 내부의 텍스트를 동적으로 변경합니다."검색"이라는 단어.ID 특성을 가진 내부 태그 "font"를 만들었습니다.javascript로 내용 관리 (아래)

서치

스크립트 내용:

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

특정 상황에서 방향이 변경되었을 때 안드로이드용 크롬에서 사라지던 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>

찌르고 찌르고 찌르고 그리고 여기서 제공되는 진부한 해결책에 만족하지 못한 지 하루 반이 지난 후, 저는 이 문제가 새로운 것을 그리는 동안 요소를 기억에 간직하는 것처럼 보이는 사실 때문에 발생했다는 것을 발견했습니다.해결책은 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'
}

제가 좀 더 엉뚱한 답변을 해봤지만 저에게는 통하지 않습니다.다른 브라우저와 비교하여 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를 다시 가져오려고 하면 사파리에서 잘못된 값을 얻는데 getter는 다음 사이에 있어야 하기 때문에 정말 이상합니다.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

문제는 초점을 잃고 상태를 스크롤한다는 것입니다.

이 코드는 CSS를 다시 렌더링합니다.

 document.body.style.display = 'flex';
 setTimeout(() => (document.body.style.display = ''), 0);

변환 CSS를 다음으로scale(0.9999)최신 크롬에서 작동하는 것 같습니다.

function redraw(node){
     // Adjust the 200 as fastest as you can
     // or, change the setTimeout to requestAnimationFrame as soon as the element
     // is drawn
     setTimeout(() => (node.style.transform = "scale(0.9999)"), 200);
}

저는 @morewry의 훌륭한 답변으로 제 문제가 해결되었다는 것을 발견했고, 더 나아가서는will-change그 이후에 도착한 재산.

CSS will-change 또는 다른 후속 사양이 미래의 해결책이 될 것입니다.

저의 경우, 그 가치는will-change: transform;사파리 14에서 단독으로 효과가 있었습니다.

.wont-update {
    will-change: transform;

    /* for Safari < 9.1 */
    transform: translateZ(0);
}

저도 Angular 10과 같은 문제에 직면했습니다.여러 가지 해결책을 시도해 보았지만 효과가 없는 것 같습니다.저에게 효과가 있었던 수정은 JS를 통해 처리하는 것입니다.방금 DOM에서 요소를 제거하고 ngIf를 사용하여 다시 추가했습니다.

HTML:

<div *ngIf="showElement">
  Contents of your element
</div>

JS:

this.showElement = false;
setTimeout(() => {
  this.showElement = true;
}, 10);

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

반응형