Чтобы ясно понять ситуацию, вам нужно понять связь между CSSOM и DOM.
В предыдущем Q / A я немного развил то, как redraw процесс работает.
По сути, есть три шага: манипулирование DOM, перекомпоновка и рисование.
- Первый ( манипулирование DOM ) просто модифицируетобъект js, и все это синхронно.
- Второй ( reflow , он же layout ) - это тот, который нас интересует, и он немного сложнее, поскольку нужны только некоторые методы DOM и операция рисованияЭто.Он состоит в обновлении всех правил CSS и пересчете всех вычисленных стилей для каждого элемента на странице.
Будучи довольно сложной операцией, браузеры будут пытаться делать это как можно реже. - Третий ( рисование ) выполняется не более 60 раз в секунду при максимуме (только при необходимости).
Переходы CSS работают путем перехода из одного состояния в другое.И чтобы сделать это, они смотрят на последнее вычисленное значение вашего элемента, чтобы создать начальное состояние.
Поскольку браузеры пересчитывают вычисленные стили только тогда, когда это требуется, в момент начала перехода ни один изприменяемые вами DOM-манипуляции еще эффективны.
Итак, в вашем первом сценарии, когда рассчитывается начальное состояние перехода, у нас есть
.b { computedStyle: {display: none} }
... и все.
Потому что, да, вот насколько мощным является display: none
для CSSOM;если элемент имеет display: none
, то его не нужно рисовать, он не существует.
Так что я даже не уверен, что алгоритм перехода сработает, но даже если бы он это сделал, начальное состояние было бы недопустимым для любого переходного значения, поскольку все вычисленные значения простоnull.
Ваш элемент .a
, видимый с начала, не имеет этой проблемы и может быть перенесен.
И если вы можете заставить его работать с задержкой (вызванной $.animate
), это потому, что между DOM-манипулятором ', который действительно изменил свойство display
, и выполнением этого отложенного DOM-манипулятора'который запускает переход, браузер запустил reflow (например, из-за того, что сработала v-синхронизация экрана и что операция paint сработала).
Теперь, это не часть вопроса, но, поскольку мы лучше понимаем, что происходит, мы также можем лучше контролировать его .
Действительно, некоторые методы DOM необходимо иметь обновленные расчетные значения.Например, Element.getBoundingClientRect
, или element.offsetHeight
, или getComputedStyle(element).height
и т. Д. Все это требует всей страницы , чтобы обновлять вычисленные значения, чтобы бокс создавался правильно (например, элемент мог иметь толчок поляболее или менее, и т. д.).
Это означает, что нам не нужно быть в неизвестном, когда браузер сработает reflow , мы можем заставить его это сделатькогда мы хотим.
Но помните, все элементы на странице должны быть обновлены, это не маленькая операция, и если браузеры снисходительны сделать это, есть веская причина.
Так что лучше используйте его время от времени, не чаще, чем один раз за кадр.
К счастью, веб-API дали нам возможность перехватить некоторый js-код непосредственно перед выполнением этой операции рисования: requestAnimationFrame .
Так что лучше всего - принудительно выполнить перекомпоновку.только один раз в этом обратном вызове перед рисованием, и для вызова всего, что требует обновленных значений из этого обратного вызова.
$('button').on('click',function(){
$('.b').show(); // apply display:block synchronously
requestAnimationFrame(() => { // wait just before the next paint
document.body.offsetHeight; // force a reflow
// trigger the transitions
$('.b').css('right','80%');
$('.a').css('right','80%');
});
})
body {
width:800px;
height:800px;
}
div {
width:50px;
height:50px;
background-color:#333;
position:absolute;
display:none;
right:5%;
top:0;
transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
color: white;
}
.a {
display:block;
top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>
Но, честно говоря, это не всегда легко настроить, поэтому, если вы уверены, что это то, что будет запускаться спорадически, вы можетебыть ленивым и делать все это синхронно:
$('button').on('click',function(){
$('.b').show(); // apply display:block
document.body.offsetHeight; // force a reflow
// trigger the transitions
$('.b').css('right','80%');
$('.a').css('right','80%');
})
body {
width:800px;
height:800px;
}
div {
width:50px;
height:50px;
background-color:#333;
position:absolute;
display:none;
right:5%;
top:0;
transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
color: white;
}
.a {
display:block;
top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>