Нам понадобится более крупный API!

[ad_1]
⭐
Нам понадобится более крупный API!
Всем нравится то, что ходит по Сети, верно? Вспомни, как ты плакал радостными слезами, когда впервые употребил <marquee>
? Я делаю. Я чуть не выплакала всю воду из своего тела, глядя на надпись «КЛАССНЫЙ ВЕБ-САЙТ ДЖЕЙКА», качающуюся туда-сюда заглавными засечками.
Конечно, в наши дни мы стали более зрелой отраслью.
Мы узнали, что пользователи не хотят, чтобы веб-сайты выглядели как консоль CSI, переживающая личный кризис; вместо этого мы стремимся к плавным переходам, которые улучшают опыт, а не сами являются им. Что касается API-интерфейсов анимации, нас плохо обслужили, и нам пришлось ковыряться с таймерами, которые на самом деле не были созданы для анимации. Ситуация в этой области неуклонно улучшается, но новая спецификация веб-анимации, похоже, сильно ее встряхнет.
Дальнейшее чтение на SmashingMag:
- Руководство по CSS-анимации: принципы и примеры
- Переходы CSS3: слава богу, у нас есть спецификация!
- Состояние анимации 2014
- Введение в анимацию ключевых кадров CSS3
Итак, зачем нам нужна новая спецификация анимации? Разве у нас уже недостаточно способов оживить вещи?
Оптимизация способа заставить вещи двигаться. (Источник изображения)
Давайте анимируем вещь!
Представьте, что мы хотим анимировать что-то по горизонтали из одного левого положения в другое в течение трех секунд, а затем что-то делать по завершении. Мы можем сделать это без JavaScript, используя анимацию CSS, но если начальная и конечная позиции определяются программно, то нам нужно что-то, чем мы можем управлять из скрипта.
С использованием requestAnimationFrame
Если вы выполняете визуальные обновления с помощью JavaScript, вам следует использовать requestAnimationFrame
. Он синхронизируется с реальными обновлениями экрана, давая вам как можно больше времени, чтобы все было готово к рендерингу. Если браузер работает на экране с частотой 60 Гц (большинство из них) и ваши кадры могут быть построены менее чем за 60-ю долю секунды, вы получите 60 кадров в секунду (FPS). requestAnimationFrame
предотвращает создание кадров, которые не успевают отображаться. Синхронизация с частотой экрана важна; 30 кадров в секунду выглядят более плавно, чем 40 кадров в секунду, потому что 40 не делится на собственные 60 Гц экрана. В HTML5 Rocks есть отличная статья о синхронизации с экраном.
К сожалению, jQuery использует setInterval
что не так гладко, как requestAnimationFrame
. requestAnimationFrame
не срабатывает, пока вкладка или окно не видны, что Хорошая вещь™. К сожалению, это создало обратную несовместимость с веб-сайтами, которые полагаются на setInterval
менее оптимальное поведение продолжения работы в фоновом режиме. Вы можете выбрать requestAnimationFrame
через плагин. Идите и добавьте это на все свои страницы, используя анимацию jQuery сейчас — я обещаю ждать вас — просто убедитесь, что переключение вкладок не сломает вашу анимацию.
Впрочем, хватит болтать. Вот простая анимация с использованием raf
перемещая коробку по горизонтали из 250px
к 500px
. Обратите внимание, что поле начинается с 0px
так что есть переход к 250px
когда начинается анимация; это доказывает, что мы можем начать анимацию с точки, отличной от текущей отображаемой позиции.
Вот код:
// On button press… animateLeft(elm, ‘250px’, ‘500px’, function() { console.log(“Done!”); });
// The implementation
function animateLeft(elm, from, to, done) { // Turn our CSS values into numbers // We’re being lazy and assuming they’re in px from = parseInt(from, 10); to = parseInt(to, 10); // Work out the amount we need to move the box var diff = to - from;var duration = 3000; var startTime = performance.now();
// Set initial position elm.style.transform = ‘translate(’ + from + ‘px, 0)’;
function frame(time) { // How long has the animation been running? var animTime = time - startTime; // Are we done? if (animTime >= duration) { // It’s likely that the last rendered position wasn’t the // final position, so we set it here. elm.style.transform = ‘translate(’ + to + ‘px, 0)’;
<span class="token function">done<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment"> // What position should the box be in?
вар должность знак равно от + (анимтайм / продолжительность * разница);
вяз.стиль.трансформировать знак равно 'перевести(' + должность + 'пкс, 0)';
// Запрос следующего кадра
запросAnimationFrame(Рамка);
}
}
// запрашиваем наш первый кадр
запросAnimationFrame(Рамка);
}Приведенный выше код является идеальным в соответствии со спецификацией. В рабочем примере мне пришлось иметь дело с префиксами поставщиков на
requestAnimationFrame
иtransform
. Мы анимируем с помощьюtransform
иtranslate
скорее, чемleft
потому что они позволяют субпиксельное позиционирование и, следовательно, более плавную анимацию, что является одним из преимуществ, которые Flash так долго имел перед HTML.Это довольно большой и вонючий кусок кода чтобы просто анимировать вещь, и она стала бы намного больше, если бы мы обрабатывали разные единицы CSS и замедление. Конечно, вы можете поместить все сложные элементы в библиотеку и создать более простой API. Вот покадровая разбивка:
Это временная шкала инструментов разработчика Chrome во время выполнения анимации. Каждый кадр выполняет некоторый JavaScript, пересчитывает стиль и макет, рисует поле, а затем отправляет это на графический процессор, который объединяет его на странице. Время прорисовки несколько раз увеличивается, что приводит к толчку в анимации. Это вызвано задержками при взаимодействии с графическим процессором (серые пики) или задержками, вызванными другим JavaScript (желтые пики).
Это подчеркивает узкое место производительности анимации, управляемой JavaScript:
Здесь еще один фрагмент JavaScript делает некоторые вещи, и на это уходит 250 миллисекунд. Пока это происходит, наша анимация не может двигаться. В реальном мире, это может быть кнопка социальной сети, которая просыпается и делает что-то медленное, или это может быть какой-то ваш собственный скрипт, запускаемый взаимодействием с пользователем. В приведенном выше примере я сделал кнопку, которая выполняет
while
цикл на 250 миллисекунд (я почти уверен, что этот код есть в каждой кнопке социальных сетей). Если вы нажмете ее во время анимации, она заблокирует анимацию и будет выглядеть неприятно.Недавно я пел дифирамбы
requestAnimationFrame
для анимации холста, так почему я ненавижу его сейчас? Анимация на основе JavaScript не является плохой практикой — она дает вам полный контроль кадр за кадром и пиксель за пикселем в сочетании с<canvas>
— но возвращаться к земле JavaScript 60 раз в секунду — это излишество для DOM-анимаций, у которых есть определенное начало и конец. В идеале мы хотим рассказать браузеру все о нашей анимации и оставить его делать свое делопока мы занимаемся чем-то другим.Конечно, у нас это уже есть.
Использование CSS-переходов
.whatever { transform: translate(250px, 0); transition: transform 3s linear; } .whatever:hover { transform: translate(500px, 0); }
CSS-переходы и анимация позволяют браузеру выполнять всевозможные оптимизации, поскольку он знает конечную точку анимации. Они не блокируются JavaScript на некоторых платформах, таких как Chrome для Android и настольный Chrome с включенным многопоточным композитингом в
about:flags
(ожидайте, что многопоточный композитинг появится в большем количестве браузеров).Давайте сценарий!
function animateLeft(elm, from, to, done) { // Set initial position elm.style.transform = ‘translate(’ + from + ’, 0)’; // Define the transition type elm.style.transition = ‘all 3s linear’;
function transitionEnd(event) { // Beware of bubbled events if (event.target != elm) { return; } // Clear the transition elm.style.transition = ’; // We don’t want that listener firing for future anims elm.removeEventListener(‘transitionend’, transitionEnd);
<span class="token function">done<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
// Слушаем конец перехода
вяз.addEventListener('переходный конец', переходКонец);
// начинаем переход
вяз.стиль.трансформировать знак равно 'перевести(' + к + ', 0)';
}Вот живой пример. Это намного проще, чем наш
raf
пример, но закралась ошибка.from
игнорируется; анимация начинается с текущей позиции элемента, даже если мы явно установили что-то другое. Почему?// Set initial position elm.style.transform = ‘translate(’ + from + ’, 0)’; // Define the transition type elm.style.transition = ‘all 3s linear’; // …and later… // Start the transition elm.style.transform = ‘translate(’ + to + ’, 0)’;
Изменение свойств в
style
object не изменяет вычисляемый стиль элемента. Стиль вычисляется только тогда, когда браузеру нужно знать, какое влияние эти стили окажут на страницу (например, когда нужно отрисовать элемент). Элемент не нужно рисовать между двумя присваиваниямиelm.style.transform
поэтому первое присваивание игнорируется.Конечно, мы можем взломать его:
// Set initial position elm.style.transform = ‘translate(’ + from + ’, 0)’; // Abracadabra! elm.offsetWidth; // Define the transition type elm.style.transition = ‘all 3s linear’; // …and later… // start the transition elm.style.transform = ‘translate(’ + to + ’, 0)’;
offsetWidth
возвращает отображаемую ширину элемента, включая отступы. Чтобы вычислить это, браузер должен учитывать все стили на странице, включаяtransform
которую мы устанавливаем для начального положения. Это работает. Посмотрите живой пример.
Производительность стабильна на уровне 60 FPS. И мы видим, что каждый кадр представляет собой простую композицию; вся тяжелая работа возложена на GPU.
Однако, опираясь на
offsetWidth
заставить элемент в исходное положение является хакерским, и вполне возможно, что будущая версия браузера найдет способ оптимизировать перекомпоновкувзломав наш хак.Рефлоу тоже не обходится без затрат:
Инструменты разработчика предупреждают нас об этом использовании
offsetWidth
, потому что браузер вычисляет макет, который он никогда не рисует. Тестовая страница очень проста, поэтому стоимость макета невелика, но в реальном мире все может быть совсем иначе.Итак, есть ли менее хакерский, более надежный способ?
Введите CSS-анимацию
Анимации CSS имеют явные значения ключевых кадров. Напишем их:
function animateLeft(elm, from, to, done) { // Create a style element for our animation var style = document.createElement(‘style’); // Generate a unique name var animName = ‘anim’ + Date.now() + Math.floor(Math.random() * 10000);
// Build the CSS style.textContent = ’ + ’@keyframes ‘ + animName + ’ { ‘ + ‘from { ‘ + ‘transform: translate(’ + from + ’, 0);’ + ’}’ + ‘to {’ ‘transform: translate(’ + to + ’, 0);’ + ’}’ + ’}’;
// Add it to the page document.head.appendChild(style);
function transitionEnd(event) { // Beware of bubbled events if (event.target != elm) { return; } // Clear the animation elm.style.animation = ’; // Clean up the DOM document.head.removeChild(style); // Retain the final position elm.style.transform = ‘translate(’ + to + ’, 0)’; // We don’t want that listener firing for future anims elm.removeEventListener(‘animationend’, transitionEnd);
<span class="token function">done<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
// Слушаем конец перехода
вяз.addEventListener('конец анимации', переходКонец);// Запускаем анимацию
вяз.стиль.анимация знак равно animName + «3 с линейно вперед»;
}Фу! И все это только для того, чтобы что-то сдвинуть? Это работает, но вся эта работа с DOM тяжела для того, чего мы пытаемся достичь. Кроме того, если анимация прерывается на полпути (например, при изменении стиля анимации), то
animationend
не будет стрелять — это означает, что нашаdone
обратный вызов не сработает или, что еще хуже, сработает в конце какой-нибудь будущей несвязанной анимации. Здесь нетanimationcancel
событие.Веб-анимация, спасите нас от этого беспорядка!
Спецификация веб-анимации только начинается, но она довольно захватывающая. Он привносит в DOM множество производительности анимации и функций синхронизации, которые в настоящее время приходится пробивать библиотекам JavaScript.
Сама спецификация какая-то пугающая. Мое сердце упало, когда я открыл страницу и увидел, что полоса прокрутки становится все меньше и меньше. Но, к счастью, в основном это детали реализации.
Вот как мы напишем нашу анимацию в дивном новом мире веб-анимации:
// Set our start position elm.style.transform = ‘translate(250px, 0)’; // Animate to the end position var anim = elm.animate({ transform: ‘translate(500px, 0)’ }, 3); // Do something on completion anim.onend = function() { console.log(‘Done!’); };
Здесь,
elm
являетсяHTMLElement
. API интуитивно понятен, особенно если вы создавали анимацию с помощью чего-то вроде jQuery.Подобно CSS-анимациям и переходам, он дает браузеру всю историю заранее, поэтому мы получаем все те же оптимизации без необходимости динамического создания CSS. Веб-анимация решает эту проблему, позволяя нам рассказать браузеру полную историю того, что мы собираемся делать. Затем браузер может отключиться и сам анимировать вещи.
Веб-анимация дает нам скриптовый API для анимации, управляемой браузером, которого очень не хватает. Выше приведен пример «Hello world». Спецификация включает в себя расширенное упрощение, анимацию на основе пути, распараллеливание, синхронизацию, прерывание и адаптацию, и все это таким образом, что браузер может отнять у земли JavaScript и соответствующим образом оптимизировать.
Это еще очень рано, поэтому пока не выбрасывайте свои библиотеки анимации. Но если вы хотите поэкспериментировать с новым API и оставить отзыв, полифилл отслеживает быстро меняющуюся спецификацию. Захватывающие времена!
(аль)
[ad_2]
Source: https://smashingmagazine.com
Заключение
Вы ознакомились с статьей — Нам понадобится более крупный API!
Пожалуйста оцените статью, и напишите комментарий.