Почему происходит переход при отображении элемента после установки свойства, когда элемент скрыт?

Живой пример можно увидеть здесь.

Красный квадрат (показан) находится прямо над зеленым квадратом (скрыт из-за переполнения). Нажмите на квадрат, и оба цветных квадрата мгновенно станут полностью прозрачными. Кроме того, высота красного квадрата установлена ​​на 0; это запускает переход, но переход остается невидимым, потому что красный квадрат теперь прозрачен.

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

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

Запуск перекомпоновки, по-видимому, заставляет применить изменение высоты. (Раскомментируйте строку, содержащую offsetParent, чтобы проверить.) Такое поведение происходит во всех браузерах (по крайней мере, в Chrome и Safari, Firefox и Opera), поэтому мне интересно, не является ли это частью какой-то спецификации. Я безуспешно проверил модуль переходов CSS. Есть идеи, почему такое поведение происходит и почему оно так согласуется между реализациями?


person Nathan Ryan    schedule 27.06.2011    source источник


Ответы (1)


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

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

Я действительно копался в этом, но не смог найти четкого решения, которое работало бы в трех основных механизмах компоновки, поддерживающих переходы (WebKit, Gecko и Presto). Тем не менее, вот что я выяснил - надеюсь, кто-то умнее меня (или просто взглянет на это свежим взглядом) сможет принять этот ответ и превратить его в верное решение.

Gecko и Presto (но не WebKit!)

Похоже (и я не разработчик браузера и не знаком со спецификацией), что любое текущее или предыдущее значение transition-property будет продолжать отображаться независимо от того, нужно это или нет. Таким образом, даже если вы изменили значение transition-property, браузер все еще отображает переход высоты в фоновом режиме, и когда вы измените высоту обратно, вы получите конец этого.

Однако есть решение: создайте transition в JavaScript (не размещайте его нигде в таблице стилей), удалите его (после чего transition правила не применяются к #upper нигде в DOM), измените высоту, а затем повторно -добавь. Не идеальный, но и не зависящий от ошибок хак.

http://jsfiddle.net/grantheaslip/e3quW/

JavaScript

upper.style.removeProperty('transition');
upper.style.removeProperty('-o-transition');
upper.style.removeProperty('-moz-transition');
upper.style.removeProperty('-webkit-transition');
upper.style.removeProperty('height');
// force a reflow
// if (upper.offsetParent) { /* empty */ }
upper.style['transition'] = 'height 1000ms';
upper.style['-o-transition'] = 'height 1000ms';
upper.style['-moz-transition'] = 'height 1000ms';
upper.style['-webkit-transition'] = 'height 1000ms';

Таблица стилей

#upper {
    background-color: red;
}

WebKit (но не Gecko или Presto!)

Все, что работает только из-за тайм-аута в 1 мс, вероятно, никогда не должно приближаться к производственной среде, но я думаю, что на это стоит указать, если это поможет кому-то разобраться в этой проблеме.

Я предполагаю, что WebKit не имеет такой же проблемы, как Presto или Gecko, а вместо этого включает оптимизацию, которая собирает изменения стиля, примененные в одной и той же функции, и применяет их все сразу. Опять же, чистая спекуляция от кого-то, кто никогда не приближался к исходному коду WebKit или спецификации CSS3.

http://jsfiddle.net/grantheaslip/DFcg9/

JavaScript

window.setTimeout(function() {
    upper.style.removeProperty('transition-property');
    upper.style.removeProperty('-o-transition-property');
    upper.style.removeProperty('-moz-transition-property');
    upper.style.removeProperty('-webkit-transition-property');
    upper.style.removeProperty('opacity');
    lower.style.removeProperty('opacity');
}, 1);

Gecko, Presto и WebKit

Вот оба решения вместе. Опять же, из-за взлома тайм-аута это действительно не следует использовать.

http://jsfiddle.net/grantheaslip/N3NrB/

person user805804    schedule 27.06.2011
comment
Этот ответ действительно вышел из-под контроля, но, надеюсь, это поможет. Если повезет, у кого-то будет быстрый ответ, который выставит меня дураком из-за того, что я упустил что-то ослепительно очевидное. - person user805804; 27.06.2011