В современных веб-приложениях вы сталкиваетесь с необходимостью анимировать элементы HTML. Будь то визуализация перехода между несколькими списками, переключение позиций в одном списке, рост элементов при выделении и т.д. Существует множество случаев, когда необходимо сделать приложение более «броским» с помощью анимации.
При этом вы заметите, что вам придется ответить на несколько вопросов. Как нам поступить с элементом, изменяющим DOM. Когда и как инициировать анимацию. Должны ли мы клонировать элемент или просто использовать его повторно. Я ни в коем случае не утверждаю, что FLIP ответит на все эти вопросы. Но он даст вам хорошую отправную точку, чтобы сделать управление анимацией немного проще.
Хитрость заключается в том, чтобы начинать не с начальной позиции элемента, а с его конечной позиции. Все это станет более понятным, когда мы опишем, что означает FLIP:
FLIP расшифровывается как First, Last, Invert and Play и был придуман Полом Льюисом.
- Первый: Начальная точка элемента. Получите эту информацию из DOM.
- Last: конечная позиция элемента. Также получите эту информацию из DOM.
- Инвертировать: Рассчитывает трансформацию (масштаб, поворот, перевод и т.д.) от первой до последней позиции и меняет ее на противоположную. Таким образом, если вам нужно анимировать 100px вправо, используйте -100px на оси x. В результате ваш элемент будет отображаться в том же положении, в котором он находился до этого.
- Play: Запустите анимацию. Теперь элемент перейдет из измененного начального положения в текущее. Больше ничего делать не нужно.
Давайте рассмотрим пример:
const flip = () => {
// retrieve the block to animate
const block1 = document.querySelector<HTMLDivElement>('#block1')
// an array with 3 target elements
const positions: Element[] = [
document.querySelector('.middle'),
document.querySelector('.end'),
document.querySelector('.start'),
]
let index = 0
if (block1) {
// animate the block on click
block1.addEventListener('click', () => {
// FLIP - First
// retrieve the position of the block at its starting point
const start = block1.getBoundingClientRect()
// Move the element to its destination
positions[index].appendChild(block1)
// FLIP - Last
// retrieve the position of the block at its final position
const end = block1.getBoundingClientRect()
// FLIP - Invert
// Calculate the change from the start to the end position
const dx = start.left - end.left
const dy = start.top - end.top
const dh = start.height - end.height
const dw = start.width - end.width
// FLIP - Play
// Initiate the animation
block1.animate(
[
{
transformOrigin: 'top left',
transform: `translate(${dx}px, ${dy}px)`,
height: `${dh}px`,
width: `${dw}px`,
},
{
transformOrigin: 'top left',
transform: 'none',
},
],
{ duration: 400, fill: 'both', easing: 'ease-in-out' }
)
index = (index + 1) % positions.length
})
}
}
При работе с FLIP вы можете столкнуться с некоторыми проблемами:
- При масштабировании элементов может возникнуть проблема со скругленными границами.
- Повернуть элемент не так просто, как кажется.
- Работа с несколькими анимациями может быть довольно сложной.
- Иногда не нужно изменять ширину или высоту элементов, а достаточно использовать преобразование масштаба. Но это усложнит работу с закругленными границами, размерами шрифтов и т.д.
В любом случае, есть хороший плагин GSAP, который поможет решить эти и другие проблемы.
Фото Liam Shaw on Unsplash