Красивое приложение должно предоставлять пользователям визуальную обратную связь. Пользователи должны всегда знать, что заказ (щелчок, нажатие или что-то еще) хорошо воспринят и понят приложением, и анимации являются отличным инструментом для этого.
Новая спецификация 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).