Красивое приложение должно предоставлять пользователям визуальную обратную связь. Пользователи должны всегда знать, что заказ (щелчок, нажатие или что-то еще) хорошо воспринят и понят приложением, и анимации являются отличным инструментом для этого.
Новая спецификация HTML 5 (честно говоря, я должен сказать «новая спецификация CSS 3 ») представляет отличный инструмент для обработки простых анимаций: переходы .
В соответствии со спецификацией «Модуль переходов CSS уровня 3» на сайте W3C , переходы CSS3 позволяют плавно изменять свойства в значениях CSS в течение указанной продолжительности .
Целью этой статьи будет сначала описать концепцию переходов, а затем посмотреть, как работает CSS3 Transitions и как мы можем работать с браузерами, которые не поддерживают эту функцию:
Кроме того, я предлагаю вам прочитать « Введение в анимацию CSS3 » (автор David Rousset ), которая является отличным компаньоном для этой статьи.
Чтобы увидеть, как можно использовать переходы CSS3, я разработал пример игры, в которой переходы CSS3 используются для анимации ячеек головоломки (и откат к JavaScript, если ваш браузер не поддерживает переходы CSS3):
CSS3 переходы
Вступление
Вначале рабочая группа CSS W3C сопротивлялась добавлению переходов в CSS, утверждая, что переходы на самом деле не являются стилевыми свойствами. Но в итоге дизайнерам и разработчикам удалось убедить их, что переходы связаны с динамическими стилями и могут происходить в файле CSS.
Согласно сайту W3C, CSS3 Transitions может анимировать следующие типы свойств: (нажмите здесь, чтобы показать их)
- цвет : интерполируется с помощью красного, зеленого, синего и альфа-компонентов (каждый рассматривается как число, см. ниже)
- длина : интерполируется как действительные числа.
- Процент : интерполируется как действительные числа.
- целое число : интерполируется через дискретные шаги (целые числа). Интерполяция происходит в реальном числовом пространстве и преобразуется в целое число с помощью floor ().
- число : интерполируется как действительные (с плавающей запятой) числа.
- список трансформации : см. спецификацию CSS Transforms: http://www.w3.org/TR/css3-2d-transforms/
- прямоугольник : интерполируется через компоненты x, y, width и height (обрабатывая каждый как число).
- видимость : интерполируется через дискретный шаг. Интерполяция происходит в реальном числовом пространстве между 0 и 1, где 1 «видимо», а все остальные значения «скрыты».
- shadow : интерполируется через компоненты color, x, y и blur (обрабатывая их как цвет и числа, где это уместно). В случае, когда есть списки теней, более короткий список заполняется в конце тенями, цвет которых прозрачен, а все длины (x, y, blur) равны 0.
- градиент : интерполируется через позиции и цвета каждой остановки. Они должны иметь одинаковый тип (радиальный или линейный) и одинаковое количество остановок для анимации.
- сервер рисования (SVG): интерполяция поддерживается только между: градиент в градиент и цвет в цвет. Затем они работают, как указано выше.
- Список разделенных пробелами выше : если списки имеют одинаковое количество элементов, каждый элемент в списке интерполируется с использованием приведенных выше правил. В противном случае, нет интерполяции.
- свойство сокращения : если все части сокращения могут быть анимированы, тогда интерполяция выполняется так, как если бы каждое свойство было задано индивидуально.
И следующие свойства должны поддерживаться для переходов: (нажмите здесь, чтобы показать их)
- цвет фона ( цвет )
- фоновое изображение ( только градиенты )
- background-position ( процент и длина )
- цвет рамки нижний ( цвет )
- граница нижней ширины ( длина )
- бордюрный цвет ( цвет )
- Цвет рамки слева ( цвет )
- border-left-width ( длина )
- рамка-цвет справа ( цвет )
- border-right-width ( длина )
- интервал границы ( длина )
- пограничный верхний цвет ( цвет )
- border-top-width ( длина )
- ширина бордюра ( длина )
- низ ( длина и процент )
- цвет ( цвет )
- обрезать ( прямоугольник )
- размер шрифта ( длина и процент )
- Вес шрифта ( число )
- сеточного * ( различные )
- высота ( длина и процент )
- слева ( длина и процент )
- межбуквенный интервал ( длина )
- высота строки ( число, длина и процент )
- нижнее поле ( длина )
- поле слева ( длина )
- поле справа ( длина )
- поле-вершина ( длина )
- максимальная высота ( длина и процент )
- максимальная ширина ( длина и процент )
- минимальная высота ( длина и процент )
- минимальная ширина ( длина и процент )
- непрозрачность ( число )
- цвет контура ( цвет )
- контурное смещение ( целое число )
- контурная ширина ( длина )
- padding-bottom ( длина )
- отступ слева ( длина )
- правый отступ ( длина )
- padding-top ( длина )
- справа ( длина и процент )
- текстовый отступ ( длина и процент )
- текстовая тень ( тень )
- верх ( длина и процент )
- выравнивание по вертикали ( ключевые слова, длина и процент )
- видимость ( видимость )
- ширина ( длина и процент )
- интервал между словами ( длина и процент )
- z-индекс ( целое число )
- зум ( число )
SVG
Свойства объектов SVG являются анимируемыми, когда они определены как animatable: true в спецификации SVG: http://www.w3.org/TR/SVG/struct.html .
Объявления
Чтобы объявить переход в файле CSS, вам просто нужно написать следующий код:
69.transition-property: all; 70.transition-duration: 0.5s; 71.transition-timing-function: ease; 72.transition-delay: 0s;
Это объявление определяет, что любое обновление любого свойства будет выполнено за 0,5 с (а не сразу).
Вы также можете определить свои переводы для каждого свойства:
73.transition-property: opacity left top; 74.transition-duration: 0.5s 0.8s 0.1s; 75.transition-timing-function: ease linear ease; 76.transition-delay: 0s 0s 1s;
И, наконец, вы можете использовать сокращенное свойство « Переход », чтобы определить все, что вам нужно в одной строке:
77.transition: all 0.5s ease 0s;
В этой сокращенной версии вы можете указать столько свойств, сколько вы хотите, через запятую:
78.transition: opacity 0.5s ease 0s, left 0.8s linear 0s;
Переходы будут срабатывать при обновлении свойства целевого объекта. Обновление можно выполнить с помощью JavaScript или CSS3, назначив новый класс тегу .
Например, используя IE10, если у вас есть следующее объявление CSS3:
79.-ms-transition-property: opacity left top; 80.-ms-transition-duration: 0.5s 0.8s 0.5s; 81.-ms-transition-timing-function: ease linear ease;
Когда вы обновите непрозрачность вашего тега, текущее значение будет анимировано до нового значения в течение 0,5 с с помощью функции замедления по времени (которая обеспечивает плавную анимацию).
Нелинейные переходы
Строка «transition-timer-function» определяет, что переход не будет линейным, но будет использовать функцию хронирования для создания нелинейной анимации.
По сути, переходы CSS3 будут использовать кубическую кривую Безье для сглаживания перехода путем вычисления различной скорости в течение его продолжительности.
Поддерживаются следующие функции:
- линейный : постоянная скорость
- cubic-bezier : Скорость будет рассчитываться в соответствии с кубической кривой Безье, определяемой двумя контрольными точками: P0 и P1 (поэтому вам нужно будет определить 4 значения здесь: P0x, P0y и P1x, P1y.
- легкость : скорость будет вычислена с помощью кубического Безье (0,25, 0,1, 0,25, 1)
- непринужденность : скорость будет вычислена с помощью кубического Безье (0,42, 0, 1, 1)
- easy-inout : скорость будет вычислена с помощью кубического Безье (0,42, 0, 0,58, 1)
- замедление : скорость будет вычислена с помощью кубического Безье (0, 0, 0,58, 1)
Вот инструмент моделирования (использующий SVG, конечно), чтобы показать влияние каждой функции синхронизации:
<p> Ваш браузер не поддерживает iframes. </ p> Нажмите здесь, чтобы показать демонстрацию: <a href=»http://www.catuhe.com/msdn/transitions/easingfunctions.htm»> http: // www .catuhe.com / MSDN / переходы / easingfunctions.htm </a>
Этот симулятор написан с чистым кодом JavaScript, чтобы облегчить понимание функции:
88.TRANSITIONSHELPER.computeCubicBezierCurveInterpolation = function (t, x1, y1, x2, y2) {
89.// Extract X (which is equal to time here)
90.var f0 = 1 - 3 * x2 + 3 * x1;
91.var f1 = 3 * x2 - 6 * x1;
92.var f2 = 3 * x1;
93.
94.var refinedT = t;
95.for (var i = 0; i < 5; i++) {
96.var refinedT2 = refinedT * refinedT;
97.var refinedT3 = refinedT2 * refinedT;
98.
99.var x = f0 * refinedT3 + f1 * refinedT2 + f2 * refinedT;
100. var slope = 1.0 / (3.0 * f0 * refinedT2 + 2.0 * f1 * refinedT + f2);
101. refinedT -= (x - t) * slope;
102. refinedT = Math.min(1, Math.max(0, refinedT));
103. }
104.
105. // Resolve cubic bezier for the given x
106. return 3 * Math.pow(1 - refinedT, 2) * refinedT * y1 +
107. 3 * (1 - refinedT) * Math.pow(refinedT, 2) * y2 +
108. Math.pow(refinedT, 3);
109. };
Этот код является реализацией кубического Безье на основе этого определения, и вы можете найти источник симулятора здесь .
задержка
Строка «transition-delay» определяет задержку между обновлением свойства и началом перехода
События
Событие возникает в конце перехода: « TransitionEnd ». В соответствии с вашим браузером правильное имя будет:
- Chrome & Safari: webkitTransitionEnd
- Firefox: mozTransitionEnd
- Опера: oTransitionEnd
- Internet Explorer: MSTransitionEnd
Событие предоставит вам следующую информацию:
- propertyName : имя анимированного свойства
- elapsedTime : время выполнения перехода в секундах.
Вот пример использования для IE10: 116. block.addEventListener («MSTransitionEnd», onTransitionEvent);
Подробнее о переходах CSS3
В основном я могу предложить две причины, по которым переходы CSS3 действительно полезны:
- Аппаратное ускорение: переходы CSS3 напрямую обрабатываются на графическом процессоре (если он доступен) и дают более плавные результаты. И это действительно важно на мобильных устройствах, где вычислительная мощность действительно ограничена
- Лучшее разделение между кодом и дизайном : для меня разработчик не должен знать об анимации или чем-либо, связанном с дизайном. Точно так же дизайнер / художник не должен знать о JavaScript. Вот почему CSS3 Transitions действительно интересны, так как дизайнеры могут описывать все переходы в CSS без необходимости разработчиков
Поддержка и запасной вариант
Начиная с PP3, IE10 (который можно загрузить с Windows 8 Developer Preview здесь ) поддерживает переходы CSS3:
Этот отчет был создан с помощью http://caniuse.com/#search=CSS3 переходов .
Конечно, поскольку спецификация не закончена ( рабочий проект ), вы должны использовать префиксы поставщика, такие как -ms-, -moz-, -webkit-, -o-.
Очевидно, мы видим, что нам необходимо предоставить прозрачное решение для всех типов браузеров. Наилучшим способом будет разработка API, который сможет определять поддержку переходов CSS3. Если браузер не поддерживает эту функцию, мы вернемся к некоторому коду JavaScript.
Важно поддерживать запасной метод, если вы полагаетесь на переходы для функциональности веб-сайтов. Если вы не хотите этого делать, вам следует рассмотреть возможность использования переходов только для улучшения дизайна . В этом случае сайт все еще будет работать, но только поддерживаемые браузеры будут работать в полном объеме. Мы говорим здесь о « прогрессивных улучшениях », поскольку чем мощнее браузер, тем больше возможностей он получает.
Переходы без переходов CSS3
Таким образом, чтобы иметь возможность поддерживать откат к переходам CSS3, мы разработаем небольшой инструментарий для обеспечения переходов по коду.
Прежде всего, мы создадим объект контейнера для нашего пространства имен:
119. var TRANSITIONSHELPER = TRANSITIONSHELPER || {};
120.
121. TRANSITIONSHELPER.tickIntervalID = 0;
122.
123. TRANSITIONSHELPER.easingFunctions = {
124. linear:0,
125. ease:1,
126. easein:2,
127. easeout:3,
128. easeinout:4,
129. custom:5
130. };
131.
132. TRANSITIONSHELPER.currentTransitions = [];
Чтобы поддерживать одинаковый уровень функций замедления, мы должны объявить enum со всеми необходимыми полями.
Инструментарий основан на функции, которая вызывается каждые 17 мс (для достижения анимации при 60 кадрах в секунду). Функция будет перечислять через коллекцию активных переходов. Для каждого перехода код будет оценивать следующее значение с учетом текущего значения и целевого значения.
Нам понадобятся некоторые удобные функции для извлечения значений используемых свойств и единиц:
133. TRANSITIONSHELPER.extractValue = function (string) {
134. try {
135. var result = parseFloat(string);
136.
137. if (isNaN(result)) {
138. return 0;
139. }
140.
141. return result;
142. } catch (e) {
143. return 0;
144. }
145. };
146.
147. TRANSITIONSHELPER.extractUnit = function (string) {
148.
149. // if value is empty we assume that it is px
150. if (string == "") {
151. return "px";
152. }
153.
154. var value = TRANSITIONSHELPER.extractValue(string);
155. var unit = string.replace(value, "");
156.
157. return unit;
158. };
Основная функция обработает активные переходы и вызовет функцию кубического Безье для оценки текущих значений:
159. TRANSITIONSHELPER.tick = function () {
160. // Processing transitions
161. for (var index = 0; index < TRANSITIONSHELPER.currentTransitions.length; index++) {
162. var transition = TRANSITIONSHELPER.currentTransitions[index];
163.
164. // compute new value
165. var currentDate = (new Date).getTime();
166. var diff = currentDate - transition.startDate;
167.
168. var step = diff / transition.duration;
169. var offset = 1;
170.
171. // Timing function
172. switch (transition.ease) {
173. case TRANSITIONSHELPER.easingFunctions.linear:
174. offset = TRANSITIONSHELPER.computeCubicBezierCurveInterpolation(step, 0, 0, 1.0, 1.0);
175. break;
176. case TRANSITIONSHELPER.easingFunctions.ease:
177. offset = TRANSITIONSHELPER.computeCubicBezierCurveInterpolation(step, 0.25, 0.1, 0.25, 1.0);
178. break;
179. case TRANSITIONSHELPER.easingFunctions.easein:
180. offset = TRANSITIONSHELPER.computeCubicBezierCurveInterpolation(step, 0.42, 0, 1.0, 1.0);
181. break;
182. case TRANSITIONSHELPER.easingFunctions.easeout:
183. offset = TRANSITIONSHELPER.computeCubicBezierCurveInterpolation(step, 0, 0, 0.58, 1.0);
184. break;
185. case TRANSITIONSHELPER.easingFunctions.easeinout:
186. offset = TRANSITIONSHELPER.computeCubicBezierCurveInterpolation(step,0.42, 0, 0.58, 1.0);
187. break;
188. case TRANSITIONSHELPER.easingFunctions.custom:
189. offset = TRANSITIONSHELPER.computeCubicBezierCurveInterpolation(step, transition.customEaseP1X, transition.customEaseP1Y, transition.customEaseP2X, transition.customEaseP2Y);
190. break;
191. }
192.
193. offset *= (transition.finalValue - transition.originalValue);
194.
195. var unit = TRANSITIONSHELPER.extractUnit(transition.target.style[transition.property]);
196. var currentValue = transition.originalValue + offset;
197.
198. transition.currentDate = currentDate;
199.
200. // Dead transition?
201. if (currentDate >= transition.startDate + transition.duration) {
202. currentValue = transition.finalValue; // Clamping
203. TRANSITIONSHELPER.currentTransitions.splice(index, 1); // Removing transition
204. index--;
205.
206. // Completion event
207. if (transition.onCompletion) {
208. transition.onCompletion({propertyName:transition.property,elapsedTime:transition.duration});
209. }
210. }
211.
212. // Affect it
213. transition.target.style[transition.property] = currentValue + unit;
214. }
215. };
Текущая версия инструментария поддерживает только числовые значения, но если вы хотите анимировать сложные значения (например, цвет), вам просто нужно разложить их на простые значения.
Регистрация перехода в системе будет осуществляться с использованием следующего кода:
216. TRANSITIONSHELPER.transition = function (target, property, newValue, duration, ease, customEaseP1X, customEaseP1Y,
customEaseP2X, customEaseP2Y, onCompletion) {
217.
218. // Create a new transition
219. var transition = {
220. target: target,
221. property: property,
222. finalValue: newValue,
223. originalValue: TRANSITIONSHELPER.extractValue(target.style[property]),
224. duration: duration,
225. startDate: (new Date).getTime(),
226. currentDate: (new Date).getTime(),
227. ease:ease,
228. customEaseP1X:customEaseP1X,
229. customEaseP2X:customEaseP2X,
230. customEaseP1Y: customEaseP1Y,
231. customEaseP2Y: customEaseP2Y,
232. onCompletion: onCompletion
233. };
234.
235. // Launching the tick service if required
236. if (TRANSITIONSHELPER.tickIntervalID == 0) {
237. TRANSITIONSHELPER.tickIntervalID = setInterval(TRANSITIONSHELPER.tick, 17);
238. }
239.
240. // Remove previous transitions on same property and target
241. for (var index = 0; index < TRANSITIONSHELPER.currentTransitions.length; index++) {
242. var temp = TRANSITIONSHELPER.currentTransitions[index];
243.
244. if (temp.target === transition.target && temp.property === transition.property) {
245. TRANSITIONSHELPER.currentTransitions.splice(index, 1);
246. index--;
247. }
248. }
249.
250. // Register
251. if (transition.originalValue != transition.finalValue) {
252. TRANSITIONSHELPER.currentTransitions.push(transition);
253. }
254. };
Функция «галочка» запускается при активации первого перехода.
Наконец, вам просто нужно использовать modernizr, чтобы определить, поддерживается ли переходы CSS3 текущим браузером. Если нет, то вы можете Откат к нашему инструментарию.
Код для TransitionsHelper можно скачать здесь: http://www.catuhe.com/msdn/transitions/transitionshelper.js
Например, в моей игре-головоломке для анимации ячеек используется следующий код:
255. if (!PUZZLE.isTransitionsSupported) {
256. TRANSITIONSHELPER.transition(block.div, "top", block.x * totalSize + offset, 500, TRANSITIONSHELPER.easingFunctions.ease);
257. TRANSITIONSHELPER.transition(block.div, "left", block.y * totalSize + offset, 500, TRANSITIONSHELPER.easingFunctions.ease);
258. }
259. else {
260. block.div.style.top = (block.x * totalSize + offset) + "px";
261. block.div.style.left = (block.y * totalSize + offset) + "px";
262. }
Мы можем заметить, что я мог бы использовать другой способ для анимации моих ячеек, когда поддерживаются переходы CSS3: я мог бы определить коллекцию классов CSS3 с предопределенными левым и верхним значениями (по одному для каждой ячейки), чтобы воздействовать на них для правых ячеек.
Некоторые платформы и наборы инструментов уже существуют для поддержки программных переходов:
- jQuery.transition.js : http://louisremi.github.com/jquery.transition.js/test/index.html
- jQUery-Animate-Enhanced: https://github.com/benbarnett/jQuery-Animate-Enhanced
Кстати, вы также можете использовать старый добрый метод animate () jQuery.
Вывод
Как мы уже видели, CSS3 Transitions — это действительно простой способ добавить анимацию в ваш проект. Вы можете создать более реактивное приложение, просто используя некоторые переходы, когда вы хотите изменить значения.
Кстати, есть два решения, если вы хотите реализовать запасной вариант JavaScript:
- Вы можете делать все на стороне JavaScript, и если вы обнаружите поддержку переходов CSS3, вы добавите объявления CSS3 на страницу.
- Или вы можете использовать стандартный способ (используя настоящие объявления CSS3 в файлах CSS) и просто обнаружить необходимость возврата в JavaScript. Для меня это лучший вариант, поскольку запасной вариант должен быть вариантом, а не основным предметом. В ближайшем будущем все браузеры будут поддерживать переходы CSS3, и в этом случае вам просто нужно будет удалить запасной код. Кроме того, это лучший способ оставить весь CSS под контролем творческой группы, а не в части кода.
Идти дальше
- Блог о анимации CSS3 Дэвида Руссе: http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animations.aspx
- Спецификации переходов CSS3: http://www.w3.org/TR/css3-transitions/
- IE Test Drive на переходах CSS3: http://ie.microsoft.com/testdrive/Graphics/hands-on-css3/hands-on_transitions.htm
- Другие полезные посты:
Лицензия
Эта статья, наряду со всеми связанными исходным кодом и файлами, распространяется под лицензией The Code Project Open License (CPOL).