Оптимизация DOM анимации. Приоритетность оптимизаций.
Постарался упорядочить действия, направленные на оптимизацию DOM/CSS анимации, в порядке эффективности. Чем выше оптимизация в списке, тем больший прирост производительности она обычно дает.
1. Изоляция анимируемого блока
По максимуму стараемся изолировать анимируемый блок, тем самым сокращаем количество элементов участвующих в анимации.
Оборачиваем анимированный участок в контейнер с четко заданным набором CSS свойств:
2. Сокращение количество reflow, repaint, recalculate
Оптимизируем неэффективные участки Javascript:
- свести к минимуму манипуляции с DOM (добавление/удаление/поиск узлов);
- innerHTML или innerHTML + join (собирать строки через join, а не обычным +) вместо многочисленных appendChild;
- кешируем значения свойств объектов, особенно таких как размеры (offsetWidth, offsetHeight ) и положение (offsetTop, offsetLeft, scrollTop, scrollLeft, scrollWidth, scrollHeight, clientTop, clientLeft, clientWidth, clientHeight), а также получение всех текущих стилей (getComputedStyle / currentStyle). Приводит к принудительным reflow и repaint;
- изменение CSS свойств одной операцией (добавление класса или cssText);
- изменение свойств объектов делать в скрытых блоках, а так же группировать изменения;
- анимацию лучше делать с абсолютно позиционируемыми элементами;
- эффективное использование таймеров, а еще лучше - requestAnimationFrame (для IE10, FF, Chrome, Safari6, iOs 5+).
3. Избавиться от тяжелых CSS3 свойств
- rotate (очень тяжелый)
- border-radius (тяжелый)
- box-shadow (очень тяжелый для FF)
- scale (пока под вопросом)
4. Сократить количество DOM узлов, участвующих в анимации
Индивидуально для каждого случая. Например, если в данный момент пользователь не видит какие-то элементы, их можно удалить из DOM перед анимацией.
5. Аппаратное ускорение
Включается при использовании CSS transform и CSS keyframes. Включается у FF, Chrome, Safari, Opera (ей не оч помогает), заявлено IE10.
Если после этой оптимизации все еще прилично тормозит, далее идти нет смысла. Нужно либо что-то еще пробовать по вышеперечисленным, либо пересматривать сценарий анимации в целом.
6. Сократить глубину DOM узлов в анимируемом блоке
Хорошо подумать и переверстать. Возможно что-то упростить в дизайне, возможно что-то реализовать на JS. По возможности избавится от таблиц.
7. Размеры изображениям
Указывая четкие размеры изображениям ускоряем reflow и repaint.
8. Сократить/оптимизировать CSS
- удалить неиспользуемые селекторы/правила;
- избавиться от универсальных селекторов;
- селекторы для конкретных классов/id, без каскадов (см. об эффективности CSS селекторов);
- не использовать float для разметки (личным опытом пока не подтверждено);
- в таблицах четкие размеры в сочетании с table-layout: fixed (личным опытом пока не подтверждено).
проанализировать эффективность CSS поможет csslint.
Если ничего не помогло
Пересмотреть сценарий анимации и/или дизайн.
Некоторые наблюдения / заметки
- общий контейнер позиционировать абсолютом. Иначе перерисовываться будет весь экран. (если в анимации происходят layout для общего контейнера). например, slideDown;
- анимации с изменением размеров элементов, перемещением, изменение прозрачности, размера шрифта будут всегда затратнее, чем изменение оформления т.к. в потребуется layout;
- избегать анимации затрагивающие геометрию body (перекомпановка/перерисовка всего);
- работа с documentFragment и виртуальным DOM элементом (createElement) по производительности примерно одинакова;
- если в поле есть placeholder, то идет reflow (хром как минимум). Производительность падает незначительно (если поле одно);
- на reflow/repaint нужны ресурсы и время. Например, вставляя крупный DOM узел и в это время производить анимацию вряд ли получится даже для мощного железа.
Материалы
- Reflows & Repaints: CSS Performance making your JavaScript slow?
- Скорость рендеринга страниц: исследования, замеры, автоматизация
- Rendering: repaint, reflow/relayout, restyle