Как заставить 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 ]

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

Я не могу поверить, что это все еще проблема в 2014 году. У меня только была эта проблема при обновлении поля заголовка с фиксированной позицией в левом нижнем углу страницы во время прокрутки, когда заголовок появлялся на экране. Попробовав все вышеперечисленное безуспешно, я заметил, что многие вещи были либо медленными, либо вызывали проблемы из-за создания очень коротких ретрансляций DOM и т. Д., Вызывая несколько неестественное чувство прокрутки и т. Д. *

В итоге я установил фиксированную позицию, полноразмерный div с pointer-events: none и применил ответ Данортона к этому элементу, что, кажется, вызывает перерисовку на всем экране без вмешательства в 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';
3 голосов
/ 24 июня 2015

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

//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 оказалось критически важным для перемещения второго изменения стиля за пределы текущего цикла событий.

2 голосов
/ 12 сентября 2015

Единственное решение, которое работает для меня, похоже на ответ sowasred2012:

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

У меня много проблемных блоков на странице, поэтому я изменяю свойство display корневого элемента. И я использую display: table; вместо display: none;, потому что none сбросит смещение прокрутки.

1 голос
/ 29 января 2014

Поскольку у каждого, похоже, есть свои проблемы и решения, я решил добавить кое-что, что мне подходит. В Android 4.1 с текущей версией Chrome при попытке перетащить холст внутри 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);
}

Нет мерцания экрана или реального обновления, а также уборка после себя. Никаких глобальных или классовых переменных, только локальные. В мобильных браузерах Safari / iPad и настольных браузерах ничего не мешает.

1 голос
/ 16 мая 2019

Я использую метод transform: translateZ(0);, но в некоторых случаях этого недостаточно.

Я не фанат добавления и удаления класса, поэтому я попытался найти способ решить эту проблему и получил новый хак, который хорошо работает:

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

// ios redraw fix
animation: redraw 1s linear infinite;
1 голос
/ 16 июня 2015

Я работаю над приложением ionic html5, на нескольких экранах у меня есть позиционированный элемент absolute, при прокрутке вверх или вниз на устройствах IOS (iPhone 4,5,6, 6+) у меня была ошибка перерисовки.

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

Я использую класс CSS .fixRepaint для этих элементов абсолютных позиций

.fixRepaint{
    transform: translateZ(0);
}

Это решило мою проблему, может быть, поможет кто-то

0 голосов
/ 09 марта 2014

выше предложения не работают для меня. но ниже делает.

Хотите динамически изменять текст внутри якоря. Слово «Поиск». Создан внутренний тег «шрифт» с атрибутом id. Управление содержимым с использованием JavaScript (ниже)

Search

содержание скрипта:

    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);
    }
0 голосов
/ 10 ноября 2018

Я пытался ответить больше, но он не работает для меня.У меня были проблемы с тем же 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})

Это действительно странно, потому что, если я пытаюсь снова получить clientWidth после get_safe_value, я получаю плохойзначение с safari, получатель должен быть между 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

Проблема в том, что вы теряете состояния фокуса и прокрутки.

0 голосов
/ 25 октября 2018

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

.selector {
    content: '1'
}
0 голосов
/ 26 марта 2018

Я бы порекомендовал менее хакерский и более формальный способ форсирования: используйте forceDOMReflowJS .В вашем случае ваш код будет выглядеть следующим образом.

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