Подтвердить что ты не робот

Триггерный переход CSS на добавленный элемент

Как этот вопрос наблюдается, немедленные переходы CSS на вновь добавленные элементы игнорируются - конечное состояние перехода отображается немедленно.

Например, данный CSS (префиксы опущены здесь):

.box { 
  opacity: 0;
  transition: all 2s;
  background-color: red;
  height: 100px;
  width: 100px;
}

.box.in { opacity: 1; }

Прозрачность этого элемента будет немедленно установлена ​​в 1:

// Does not animate
var $a = $('<div>')
    .addClass('box a')
    .appendTo('#wrapper');
$a.addClass('in');

Я видел несколько способов запуска перехода для получения ожидаемого поведения:

// Does animate
var $b = $('<div>')
    .addClass('box b')
    .appendTo('#wrapper');

setTimeout(function() {
    $('.b').addClass('in');
},0);

// Does animate
var $c = $('<div>')
    .addClass('box c')
    .appendTo('#wrapper');

$c[0]. offsetWidth = $c[0].offsetWidth
$c.addClass('in');

// Does animate
var $d = $('<div>')
    .addClass('box d')
    .appendTo('#wrapper');
$d.focus().addClass('in');

Те же самые методы применимы к манипуляциям с манипуляциями с JS DOM в ванили - это не поведение, специфичное для jQuery.

Изменить. Я использую Chrome 35.

JSFiddle (включает пример Vanilla JS).

  • Почему немедленные анимации CSS на присоединенных элементах игнорируются?
  • Как и почему эти методы работают?
  • Есть ли другие способы сделать это
  • Какой, если таковой имеется, является предпочтительным решением?
4b9b3361

Ответ 1

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

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

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

Существует еще одно исключение правила дозирования. Браузеру необходимо рассчитать ближайшее значение, если вы пытаетесь получить к нему доступ. Одно из этих значений - offsetWidth. Когда вы обращаетесь к нему, происходит перезапуск. Еще один выполняется отдельно во время фактического отображения. Опять же, у нас есть два разных значения стиля, поэтому мы можем интерполировать их во времени.

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

Предпочтительное решение может отличаться от человека к человеку, но для меня лучше всего подходит доступ offsetWidth (или getComputedStyle()). Бывают случаи, когда setTimeout запускается без пересчета стилей между ними. Это редкий случай, в основном на загруженных сайтах, но это происходит. Тогда вы не получите свою анимацию. Получая доступ к любому расчетному стилю, вы вынуждаете браузер фактически вычислять его.

Ответ 2

Используя jQuery попробуйте это (Пример здесь.):

var $a = $('<div>')
.addClass('box a')
.appendTo('#wrapper');
$a.css('opacity'); // added
$a.addClass('in');

Используя Vanilla javaScript, попробуйте следующее:

var e = document.createElement('div');
e.className = 'box e';
document.getElementById('wrapper').appendChild(e);
window.getComputedStyle(e).opacity; // added
e.className += ' in';

Краткая идея:

getComputedStyle() сбрасывает все ожидающие изменения стиля и заставляет механизм компоновки вычислять текущее состояние элемента, следовательно .css() работает аналогичным образом.

О css() из jQuery сайта:

Метод .css() - это удобный способ получить свойство стиля из первый согласованный элемент, особенно в свете различных способов браузеры получают доступ к большинству этих свойств (getComputedStyle() метод в браузерах на основе стандартов по сравнению с currentStyle и свойства runtimeStyle в Internet Explorer) и разные термины браузеры используют для определенных свойств.

Вместо setTimeout вы можете использовать getComputedStyle()/css(). Также вы можете прочитать эту статью для получения подробной информации и примеров.

Ответ 3

Решение @Frizi работает, но иногда я обнаружил, что getComputedStyle не работал, когда я изменяю некоторые свойства элемента. Если это не сработает, вы можете попробовать getBoundingClientRect() следующим образом, который я обнаружил как пуленепробиваемый:

Предположим, что мы имеем элемент el, на который мы хотим перейти opacity, но el есть display:none; opacity: 0:

el.style.display = 'block';
el.style.transition = 'opacity .5s linear';

// reflow
el.getBoundingClientRect();

// it transitions!
el.style.opacity = 1;

Ответ 4

Пожалуйста, используйте приведенный ниже код, используйте "focus()"

Jquery

var $a = $('<div>')
    .addClass('box a')
    .appendTo('#wrapper');
$a.focus(); // focus Added
$a.addClass('in');

Javascript

var e = document.createElement('div');
e.className = 'box e';
document.getElementById('wrapper').appendChild(e).focus(); // focus Added
e.className += ' in';

Ответ 5

Вместо того, чтобы пытаться принудительно выполнить пересчет или стиль, я попытался использовать requestAnimationFrame(), чтобы браузер мог нарисовать его следующий доступный кадр.

В Chrome + Firefox браузер оптимизирует рендеринг слишком сильно, поэтому это все равно не помогает (работает в Safari).

Я решил вручную задержать задержку с setTimeout(), затем используя requestAnimationFrame(), чтобы ответственно разрешить браузер красить. Если приложение не было написано до истечения таймаута, анимация может быть проигнорирована, но, похоже, работает надежно.

setTimeout(function () {
    requestAnimationFrame(function () {
        // trigger the animation
    });
}, 20);

Я выбрал 20 мс, потому что он больше 1 кадра со скоростью 60 кадров в секунду (16,7 мс), а некоторые браузеры не будут регистрировать тайм-ауты < 5ms.

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

Ответ 6

В отличие от Брендана, я обнаружил, что requestAnimationFrame() работает в Chrome 63, Firefox 57, IE11 и Edge.

var div = document.createElement("div");
document.body.appendChild(div);

requestAnimationFrame(function () {
  div.className = "fade";
});
div {
  height: 100px;
  width: 100px;
  background-color: red;
}

.fade {
  opacity: 0;
  transition: opacity 2s;
}

Ответ 7

Я предпочитаю requestAnimationFrame + setTimeout (см. Этот пост).

const child = document.createElement("div");
child.style.backgroundColor = "blue";
child.style.width = "100px";
child.style.height = "100px";
child.style.transition = "1s";

parent.appendChild(child);

requestAnimationFrame(() =>
  setTimeout(() => {
    child.style.width = "200px";
  })
);

Попробуй это здесь.