Как заставить WebKit перерисовать / перекрасить для распространения изменений стиля? - PullRequest
241 голосов
/ 15 августа 2010

У меня есть тривиальный 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 .

В Chrome «Инструменты разработчика»”Окно, если я подтолкну (например, уберу галочку и проверим) любой атрибут элемента любой , второй брат обновится до правильного стиля.и программно «подтолкнуть» WebKit на правильные действия?

Ответы [ 26 ]

296 голосов
/ 15 августа 2010

Я нашел несколько сложных предложений и множество простых, которые не работали, но комментарий к одному из них Василь Динков предоставил простое решение для принудительного перерисовывания / перерисовки, которое работает просто отлично:

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

Я позволю кому-нибудь еще прокомментировать, если это работает для стилей, отличных от «блока».

Спасибо, Василь!

87 голосов
/ 22 февраля 2014

Недавно мы столкнулись с этим и обнаружили, что перевод затронутого элемента в составной слой с translateZ в CSS исправил проблему, не требуя дополнительного JavaScript.

.willnotrender { 
   transform: translateZ(0); 
}

Поскольку эти проблемы рисования в основном проявляются в Webkit / Blink, и это исправление в основном предназначено для Webkit / Blink, в некоторых случаях это предпочтительно. Тем более что принятый ответ почти наверняка вызывает перекомпоновку и перерисовку , , а не просто перерисовку.

Webkit и Blink усердно работали над производительностью рендеринга, и такие глюки являются нежелательным побочным эффектом оптимизации, направленной на уменьшение ненужных потоков и красок. CSS изменится или другая последующая спецификация, скорее всего, будет будущим решением.

Существуют и другие способы создания составного слоя, но это наиболее распространенный.

51 голосов
/ 10 марта 2011

Данортон решение не работает для меня.У меня были некоторые действительно странные проблемы, когда webkit вообще не рисовал некоторые элементы;где текст на входах не обновлялся до onblur;и изменение className не приведет к перерисовке.

Мое решение, как я случайно обнаружил, было добавить пустой элемент стиля в тело после сценария.,Насколько это странно?Надеюсь, это кому-нибудь пригодится.

32 голосов
/ 01 марта 2012

Поскольку у меня не работает триггер display + offset, я нашел решение здесь:

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

т.е.

element.style.webkitTransform = 'scale(1)';
22 голосов
/ 07 декабря 2012

Я страдал от той же проблемы. Исправление «переключения отображения» Данортона сработало для меня, когда его добавили в пошаговую функцию моей анимации, но я беспокоился о производительности и искал другие варианты.

В моих обстоятельствах элемент, который не перерисовывался, находился в элементе абсолютно позиции, который в то время не имел z-индекса. Добавление z-индекса к этому элементу изменило поведение Chrome, и перерисовка произошла, как и ожидалось -> анимация стала плавной.

Я сомневаюсь, что это панацея, я думаю, что это зависит , почему Chrome решил не перерисовывать элемент, но я публикую это конкретное решение здесь, чтобы помочь кому-то.

Ура, Rob

tl; dr >> Попробуйте добавить z-индекс к элементу или его родительскому элементу.

16 голосов
/ 08 января 2014

Следующие работы.Его нужно установить только один раз в чистом CSS.И это работает более надежно, чем функция JS.Производительность кажется неизменной.

@-webkit-keyframes androidBugfix {from { padding: 0; } to { padding: 0; }}
body { -webkit-animation: androidBugfix infinite 1s; }
12 голосов
/ 17 января 2013

По какой-то причине я не смог получить ответ Данортона на работу, я мог видеть, что он должен был сделать, поэтому я немного подправил его так:

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

и у меня это сработало.

6 голосов
/ 24 марта 2013

Я пришел сюда, потому что мне нужно было перерисовать полосы прокрутки в Chrome после изменения его CSS.

Если у кого-то возникла такая же проблема, я решил ее, вызвав эту функцию:

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

Этот метод не является лучшим решением, но он может работать со всем, скрыть и показать элемент, который необходимо перерисовать, может решить любую проблему.

Вот скрипка, в которой я ее использовал: http://jsfiddle.net/promatik/wZwJz/18/

6 голосов
/ 07 сентября 2011

Я наткнулся на это сегодня: Element.redraw () для prototype.js

Использование:

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

Однако я иногда замечал, что вы должны вызывать redraw () для проблемного элемента напрямую. Иногда перерисовка родительского элемента не решит проблему, с которой сталкивается ребенок.

Хорошая статья о том, как браузеры отображают элементы: Рендеринг: перекраска, перекомпоновка / ретрансляция, рестайл

4 голосов
/ 21 июля 2014

У меня была эта проблема с рядом элементов, которые были вставлены в другой элемент с position: absolute, у вставленных элементов не было атрибута позиции.Когда я изменил это на position:relative, он работал нормально.(было действительно трудно определить проблему)

В моем случае элементы были вставлены Angular с помощью ng-repeat.

...