У меня есть элемент с неустановленной высотой. Я хочу, чтобы высота плавно переходила в желаемое значение (например, 200 пикселей). Я использую для этого requestAnimationFrame, но не могу понять, как именно это работает.
В приведенном ниже примере, если мы раскомментируем первый requestAnimationFrame и его закрывающие скобки, он будет работать именно так, как мы хотим. Но почему?
Да, я понимаю, что таким образом первое изменение высоты будет завернуто в свой собственный requestAnimationFrame, но ключевой вопрос в том, почему это имеет такое большое значение? Тем более, что второе изменение высоты уже завернуто в requestAnimationFrame. Разве это уже не делает его как бы разделенным во времени, кроме первого изменения?
Я прочитал несколько статей о requestAnimationFrame, но все еще не мог понять этот конкретный пример. Я думаю, мне нужно какое-то ручное объяснение здесь.
Пожалуйста помоги.
РЕДАКТИРОВАТЬ после получения ответа:
Это редактирование основано на ответе бархатсора.
Итак, в основном в исходном примере последовательность действий выглядит так (поправьте меня, если я не прав):
Кадр 1, действие 1. (сразу). Узнать реальную высоту элемента в пикселях
Кадр 1, действие 2. (сразу). Установите высоту элемента на его scrollHeight
Кадр 1, действие 3. (сразу). Измените высоту элемента на 200 пикселей (немедленное изменение приводит к объединению изменений)
Кадр 2, действие 1. (на следующем кадре). Браузер, когда будете готовы, анимируйте (изменения объединены — анимировать нечего)
Если мы раскомментируем первый requestAnimationFrame и его закрывающие скобки, будет ли это выглядеть так?
Кадр 1, действие 1. (сразу). Узнать реальную высоту элемента в пикселях
Кадр 1, действие 2. (сразу). Установите высоту элемента на его scrollHeight
Кадр 2, действие 1. (на следующем кадре). Браузер, когда будешь готов, анимируй
Кадр 2, действие 2. (сразу). Измените высоту элемента на 200px (изменения теперь разделены по времени на один кадр?)
Кадр 3, действие 1. (на следующем кадре). Браузер, когда будете готовы, анимируйте (анимация меняется)
Это верно? Я хотел бы увидеть вашу точку зрения на это. Может я совсем не прав?
let button = document.querySelector(".button");
let element = document.querySelector(".element");
button.addEventListener("click", triggerHeightChange);
function triggerHeightChange() {
// finding out real height of the element in pixels
let actualHeight = element.scrollHeight;
// requestAnimationFrame(function() {
// assgning height value so we aren't transitioning out of "auto"
element.style.height = actualHeight + "px";
requestAnimationFrame(function() {
// assigning desired height value
element.style.height = "200px";
})
// })
// this part is just to return element to it's initial state after transition
element.addEventListener("transitionend", function() {
element.style.height = actualHeight + "px";
element.addEventListener("transitionend", function() {
element.removeAttribute("style");
}, {once: true})
}, {once: true})
}
.element {
width: max-content;
margin: 0 auto 30px;
font-size: 40px;
background-color: gold;
transition: 0.5s height;
}
.button {
display: block;
margin: 0 auto 30px;
font-size: 20px;
}
<div class = "element">Element with an unset height</div>
<button class = "button">Change element's height from unset to 200px with smooth transition, then return it back</button>
Вы устанавливаете высоту элемента на scrollHeight
, а затем сразу же меняете ее на 200px
.
Большинство браузеров оптимизируют переходы и объединяют изменения, которые занимают менее 16 мс, поэтому переход не отображался.
Таким образом, решение состоит в том, чтобы указать браузеру анимировать, когда он будет готов, используя requestAnimationFrame()
, как в вашем коде.
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame