refactor 3-more into separate books
This commit is contained in:
parent
bd1d5e4305
commit
87639b2740
423 changed files with 9 additions and 9 deletions
28
5-animation/2-css-transitions/1-animate-logo-css/solution.md
Normal file
28
5-animation/2-css-transitions/1-animate-logo-css/solution.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Алгоритм
|
||||
|
||||
Анимируйте одновременно свойства `left/top` и `width/height`.
|
||||
|
||||
Чтобы в процессе анимации таблица сохраняла геометрию -- создайте на месте `IMG` временный `DIV` фиксированного размера и переместите `IMG` внутрь него. После анимации можно вернуть как было.
|
||||
|
||||
Для начала анимации - добавьте класс изображению:
|
||||
|
||||
```css
|
||||
.growing {
|
||||
/* все свойства анимируются 3 секунды */
|
||||
-webkit-transition: all 3s;
|
||||
-moz-transition: all 3s;
|
||||
-o-transition: all 3s;
|
||||
-ms-transition: all 3s;
|
||||
}
|
||||
```
|
||||
|
||||
При этом, чтобы анимация началась, может понадобиться отложить установку класса и новых свойств через `setTimeout(.., 0)`.
|
||||
|
||||
Для отлова конца анимации используйте событие `on<browser>TransitionEnd`. Оно сработает несколько раз, для каждого свойства, поэтому чтобы обработчик не вывел "OK" много раз -- можно обрабатывать окончание только при одном `event.propertyName`.
|
||||
|
||||
# Похожая задача
|
||||
Аналогичная задача, решённая средствами JS: [](/task/animate-logo).
|
||||
|
||||
# Решение
|
||||
|
||||
[edit src="solution" task/]
|
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>img { display: block; cursor: pointer; }</style>
|
||||
<style>
|
||||
/**
|
||||
* до анимации: .flyjet
|
||||
* в начале анимации .flyjet .growing-init
|
||||
* в процессе анимации .flyjet .growing-init .growing
|
||||
* в конце анимации .flyjet
|
||||
*/
|
||||
|
||||
.flyjet {
|
||||
width: 400px;
|
||||
height: 240px;
|
||||
}
|
||||
|
||||
.growing-init {
|
||||
position: absolute;
|
||||
height: 0;
|
||||
width: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
|
||||
/* все свойства анимируются 3 секунды */
|
||||
-webkit-transition: all 3s;
|
||||
-moz-transition: all 3s;
|
||||
-o-transition: all 3s;
|
||||
-ms-transition: all 3s;
|
||||
}
|
||||
|
||||
.growing {
|
||||
width: 400px;
|
||||
height: 240px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Кликните картинку для анимации. Расположение элементов при анимации не должно меняться!
|
||||
<table>
|
||||
<tr>
|
||||
<td>Догнать</td>
|
||||
<td><img onclick="growIn(this)" src="https://js.cx/clipart/flyjet.jpg" class="flyjet">
|
||||
</td>
|
||||
<td>..и перегнать!</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<b>В процессе анимации повторные клики на изображение игнорировать.</b>
|
||||
|
||||
<script>
|
||||
function growIn(img) {
|
||||
if (img.classList.contains('growing-init')) return;
|
||||
console.log("growIn!");
|
||||
|
||||
var height = img.offsetHeight;
|
||||
var width = img.offsetWidth;
|
||||
|
||||
// переместить изображение в placeholder постоянного размера
|
||||
var placeholder = document.createElement('div');
|
||||
placeholder.style.position = 'relative';
|
||||
placeholder.style.width = width + 'px';
|
||||
placeholder.style.height = height + 'px';
|
||||
img.parentNode.replaceChild(placeholder, img);
|
||||
placeholder.appendChild(img);
|
||||
|
||||
img.classList.add('growing-init');
|
||||
|
||||
// откладываем на следующий фрейм, чтобы началась анимация
|
||||
// иначе изменение свойств IMG не будет замечено
|
||||
requestAnimationFrame(function() {
|
||||
|
||||
// Firefox иногда не стартует анимацию,
|
||||
// если не отложить classList.add ещё на один кадр (tested: FF30-)
|
||||
requestAnimationFrame(function() {
|
||||
img.classList.add('growing');
|
||||
|
||||
img.addEventListener('transitionend', done);
|
||||
});
|
||||
});
|
||||
|
||||
function done(e) {
|
||||
// сработать только первый раз
|
||||
img.removeEventListener('transitionend', done);
|
||||
|
||||
placeholder.parentNode.replaceChild(img, placeholder);
|
||||
|
||||
img.classList.remove('growing');
|
||||
img.classList.remove('growing-init');
|
||||
|
||||
alert('ok');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
Docs: http://learn.javascript.ru/tutorial/lib
|
||||
*/
|
||||
|
||||
function animate(opts) {
|
||||
|
||||
var start = new Date;
|
||||
var delta = opts.delta || linear;
|
||||
|
||||
var timer = setInterval(function() {
|
||||
var progress = (new Date - start) / opts.duration;
|
||||
|
||||
if (progress > 1) progress = 1;
|
||||
|
||||
opts.step( delta(progress) );
|
||||
|
||||
if (progress == 1) {
|
||||
clearInterval(timer);
|
||||
opts.complete && opts.complete();
|
||||
}
|
||||
}, opts.delay || 13);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
Анимация стиля opts.prop у элемента opts.elem
|
||||
от opts.from до opts.to продолжительностью opts.duration
|
||||
в конце opts.complete
|
||||
|
||||
Например: animateProp({ elem: ..., prop: 'height', start:0, end: 100, duration: 1000 })
|
||||
*/
|
||||
function animateProp(opts) {
|
||||
var start = opts.start, end = opts.end, prop = opts.prop;
|
||||
|
||||
opts.step = function(delta) {
|
||||
var value = Math.round(start + (end - start)*delta);
|
||||
opts.elem.style[prop] = value + 'px';
|
||||
}
|
||||
return animate(opts);
|
||||
}
|
||||
|
||||
// ------------------ Delta ------------------
|
||||
|
||||
function elastic(progress) {
|
||||
return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress);
|
||||
}
|
||||
|
||||
function linear(progress) {
|
||||
return progress;
|
||||
}
|
||||
|
||||
function quad(progress) {
|
||||
return Math.pow(progress, 2);
|
||||
}
|
||||
|
||||
function quint(progress) {
|
||||
return Math.pow(progress, 5);
|
||||
}
|
||||
|
||||
function circ(progress) {
|
||||
return 1 - Math.sin(Math.acos(progress));
|
||||
}
|
||||
|
||||
function back(progress) {
|
||||
return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5);
|
||||
}
|
||||
|
||||
|
||||
function bounce(progress) {
|
||||
for(var a = 0, b = 1, result; 1; a += b, b /= 2) {
|
||||
if (progress >= (7 - 4 * a) / 11) {
|
||||
return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeEaseInOut(delta) {
|
||||
return function(progress) {
|
||||
if (progress < .5)
|
||||
return delta(2*progress) / 2;
|
||||
else
|
||||
return (2 - delta(2*(1-progress))) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function makeEaseOut(delta) {
|
||||
return function(progress) {
|
||||
return 1 - delta(1 - progress);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="animate.js"></script>
|
||||
<style>img { display: block; cursor: pointer; }</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Кликните картинку для анимации. Расположение элементов при анимации не должно меняться!
|
||||
<table>
|
||||
<tr>
|
||||
<td>Догнать</td>
|
||||
<td><img onclick="growIn(this)" src="https://js.cx/clipart/flyjet.jpg" width="400" height="240">
|
||||
</td>
|
||||
<td>..и перегнать!</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<b>В процессе анимации повторные нажатия на изображение игнорируются.</b>
|
||||
|
||||
<script>
|
||||
function growIn(img) {
|
||||
/* ваш код */
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
12
5-animation/2-css-transitions/1-animate-logo-css/task.md
Normal file
12
5-animation/2-css-transitions/1-animate-logo-css/task.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Анимировать лого (CSS)
|
||||
|
||||
[importance 5]
|
||||
|
||||
Реализуйте анимацию, как в демке ниже (клик на картинку):
|
||||
[iframe src="solution" height=350]
|
||||
|
||||
Продолжительность анимации: 3 секунды.
|
||||
|
||||
Для анимации использовать CSS, по окончании вывести "ок".
|
||||
|
||||
|
216
5-animation/2-css-transitions/article.md
Normal file
216
5-animation/2-css-transitions/article.md
Normal file
|
@ -0,0 +1,216 @@
|
|||
# CSS-transitions
|
||||
|
||||
Все современные браузеры, кроме IE9- поддерживают <a href="http://www.w3.org/TR/css3-transitions/">CSS transitions</a>, которые позволяют реализовать анимацию средствами CSS, без привлечения JavaScript.
|
||||
|
||||
[cut]
|
||||
|
||||
## Анимация свойства [#css-transition]
|
||||
|
||||
Идея проста. Вы указываете, что некоторое свойство будет анимироваться при помощи специальных CSS-правил. Далее, при изменении этого свойства, браузер сам обработает анимацию.
|
||||
|
||||
Например, CSS, представленный ниже, 2 секунды анимирует свойство `background-color`.
|
||||
|
||||
```css
|
||||
.animated {
|
||||
transition-property: background-color;
|
||||
transition-duration: 2s;
|
||||
}
|
||||
```
|
||||
|
||||
Теперь любое изменение фонового цвета будет анимироваться в течение 2-х секунд.
|
||||
|
||||
У свойства `"transition"` есть и короткая запись:
|
||||
|
||||
```css
|
||||
.animated {
|
||||
transition: background-color 2s;
|
||||
}
|
||||
```
|
||||
|
||||
## Полный синтаксис
|
||||
|
||||
Свойства для CSS-анимаций:
|
||||
<dl>
|
||||
<dt>`transition-property`</dt>
|
||||
<dd>Список свойств, которые будут анимироваться. Анимировать можно не все свойства, но [многие](http://www.w3.org/TR/css3-transitions/#animatable-properties-). Значение `all` означает "анимировать все свойства".</dd>
|
||||
<dt>`transition-duration`</dt>
|
||||
<dd>Продолжительность анимации. Если указано одно значение -- оно применится ко всем свойствам, можно указать несколько значений для разных `transition-property`.</dd>
|
||||
<dt>`transition-timing-function`</dt>
|
||||
<dd>Кривая Безье по 4-м точкам, используемая в качестве временной функциии. Их мы изучим [чуть позже](/bezier)</dd>
|
||||
<dt>`transition-delay`</dt>
|
||||
<dd>Указывает задержку от изменения свойства до начала CSS-анимации.</dd>
|
||||
</dl>
|
||||
|
||||
Свойство **`transition`** может содержать их все, в порядке: `property duration timing-function delay, ...`.
|
||||
|
||||
## Пример
|
||||
|
||||
Анимируем одновременно цвет и размер шрифта:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<style>
|
||||
.growing {
|
||||
transition: font-size 3s, color 2s;
|
||||
}
|
||||
</style>
|
||||
<button class="growing" onclick="this.style.fontSize='36px';this.style.color='red'">Кликни меня</button>
|
||||
```
|
||||
|
||||
## Временнáя функция
|
||||
|
||||
В качестве временной функции можно выбрать любую [кривую Безье](/bezier), удовлетворяющую условиям:
|
||||
<ol>
|
||||
<li>Начальная точка `(0,0)`.</li>
|
||||
<li>Конечная точка `(1,1)`.</li>
|
||||
<li>Для промежуточных точек значения `x` должны быть в интервале `0..1`.</li>
|
||||
</ol>
|
||||
|
||||
Синтаксис для задания кривой Безье в CSS: `cubic-bezier(x2, y2, x3, y3)`. В нём указываются координаты второй и третьей точек, так как первая и последняя фиксированы.
|
||||
|
||||
Например, торможение можно описать кривой Безье: `cubic-bezier(0.0, 0.5, 0.5 ,1.0)`.
|
||||
|
||||
График этой кривой:
|
||||
|
||||
<img src="train-curve.png">
|
||||
|
||||
Вы можете увидеть эту временную функцию в действии, кликнув на поезд:
|
||||
|
||||
```html
|
||||
<style>
|
||||
.train {
|
||||
position: relative;
|
||||
left: 0;
|
||||
-moz-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
-webkit-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
-ms-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
-o-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
}
|
||||
</style>
|
||||
<img class="train" width="177" height="160" src="/files/tutorial/browser/animation/train.gif" onclick="this.style.left='450px'">
|
||||
```
|
||||
|
||||
<style>
|
||||
.train {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
left: 0;
|
||||
-moz-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
-webkit-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
-ms-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
-o-transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
transition: left 5s cubic-bezier(0.0,0.5,0.5,1.0);
|
||||
}
|
||||
</style>
|
||||
<img class="train" width="177" height="160" src="/files/tutorial/browser/animation/train.gif" onclick="this.style.left='450px'">
|
||||
|
||||
|
||||
Существуют и несколько стандартных кривых: `linear`, `ease`, `ease-in`, `ease-out` и `ease-in-out`.
|
||||
|
||||
Значение `linear` -- это прямая, равномерное изменение. Оно используется по умолчанию.
|
||||
|
||||
Остальные кривые являются короткой записью следующих `cubic-bezier`. В таблице ниже показано соответствие:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>`ease`</th>
|
||||
<th>`ease-in`</th>
|
||||
<th>`ease-out`</th>
|
||||
<th>`ease-in-out`</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`(0.25, 0.1, 0.25, 1.0)`</td>
|
||||
<td>`(0.42, 0, 1.0, 1.0)`</td>
|
||||
<td>`(0, 0, 0.58, 1.0)`</td>
|
||||
<td>`(0.42, 0, 0.58, 1.0)`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="ease.png"></td>
|
||||
<td><img src="ease-in.png"></td>
|
||||
<td><img src="ease-out.png"></td>
|
||||
<td><img src="ease-in-out.png"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Наиболее близкий стандартный вариант для примера с поездом -- `ease-out`:
|
||||
|
||||
```css
|
||||
.train {
|
||||
-moz-transition: left 5s ease-out;
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## CSS-преобразования
|
||||
|
||||
Браузеры, которые поддерживают CSS-анимацию, поддерживают и [CSS-преобразования](https://developer.mozilla.org/en/CSS/Using_CSS_transforms).
|
||||
|
||||
С их помощью можно сделать много красивых эффектов. Например, вращение:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
||||
document.body.style.MozTransition = "all 5s";
|
||||
document.body.style.MozTransform = "rotate(360deg)";
|
||||
document.body.style.WebkitTransition = "all 5s";
|
||||
document.body.style.WebkitTransform = "rotate(360deg)";
|
||||
document.body.style.OTransition = "all 5s";
|
||||
document.body.style.OTransform = "rotate(360deg)";
|
||||
document.body.style.MsTransition = "all 5s";
|
||||
document.body.style.MsTransform = "rotate(360deg)";
|
||||
|
||||
document.body.style.Transition = "all 5s";
|
||||
document.body.style.Transform = "rotate(360deg)";
|
||||
```
|
||||
|
||||
Самое замечательное -- все эти эффекты используют графический ускоритель и почти не нагружают процессор.
|
||||
|
||||
Все браузеры, кроме IE9- поддерживают это, ну а в IE может быть что-то через JavaScript или вообще без анимации.
|
||||
|
||||
## Событие transitionend
|
||||
|
||||
На конец CSS-анимации можно повесить обработчик. Его стандартное имя: `transitionend`, но браузерные префиксы требуются и тут.
|
||||
|
||||
Кликните на лодочку:
|
||||
|
||||
[iframe src="boat" height=300 edit link]
|
||||
|
||||
Её анимация осуществляется функцией `go`, которая перезапускается по окончании (с переворотом через CSS).
|
||||
|
||||
```js
|
||||
...
|
||||
go();
|
||||
|
||||
elem.addEventListener('transitionend', go); /* на будущее */
|
||||
elem.addEventListener('webkitTransitionEnd', go);
|
||||
elem.addEventListener('mozTransitionEnd', go);
|
||||
elem.addEventListener('oTransitionEnd', go);
|
||||
elem.addEventListener('msTransitionEnd', go);
|
||||
...
|
||||
```
|
||||
|
||||
Объект события `transitionend` также содержит свойства:
|
||||
<dl>
|
||||
<dt>`propertyName`</dt>
|
||||
<dd>Свойство, анимация которого завершилась.</dd>
|
||||
<dt>`elapsedTime`</dt>
|
||||
<dd>Время (в секундах), которое заняла анимация, без учета `transition-delay`.</dd>
|
||||
</dl>
|
||||
|
||||
Свойство `propertyName` может быть полезно при одновременной анимации нескольких свойств. Каждое свойство даст своё событие, и можно решить, что с ним делать дальше.
|
||||
|
||||
## Ограничения и достоинства CSS-анимаций
|
||||
|
||||
[compare]
|
||||
-Основное ограничение -- это то, что временная функция может быть задана только кривой Безье. Более сложные анимации, состоящие из нескольких кривых, реализуются при помощи [CSS animations](http://dev.w3.org/csswg/css3-animations/#animation-name-property) (стандарт пока не готов).
|
||||
-CSS-анимации касаются только свойств, а в JavaScript можно делать всё, что угодно.
|
||||
-Отсутствует поддержка в IE9-
|
||||
+Простые вещи делаются просто. Особенно удобно, если от отсутствия эффекта в IE проблем не возникнет.
|
||||
+Гораздо "легче" для процессора, чем анимации JavaScript. Лучше используется графический ускоритель. Это очень важно для мобильных устройств.
|
||||
[/compare]
|
||||
|
||||
[head]
|
||||
<link type="text/css" rel="stylesheet" href="/files/tutorial/browser/animation/animate.css" />
|
||||
<script src="/files/tutorial/browser/animation/step.js"></script>
|
||||
[/head]
|
60
5-animation/2-css-transitions/boat.view/index.html
Normal file
60
5-animation/2-css-transitions/boat.view/index.html
Normal file
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
.bouncing-boat {
|
||||
margin-left: 0;
|
||||
cursor: pointer;
|
||||
-webkit-transition: margin-left 3s ease-in-out;
|
||||
-moz-transition: margin-left 3s ease-in-out;
|
||||
-o-transition: margin-left 3s ease-in-out;
|
||||
-ms-transition: margin-left 3s ease-in-out;
|
||||
}
|
||||
|
||||
/* переворот картинки через CSS */
|
||||
.flip-horizontal {
|
||||
-webkit-transform: scaleX(-1);
|
||||
-moz-transform: scaleX(-1);
|
||||
-o-transform: scaleX(-1);
|
||||
-ms-transform: scaleX(-1);
|
||||
filter: fliph; /* IE9- */
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<img src="https://js.cx/clipart/boat.png" class="bouncing-boat" onclick="bounceBoat(this)">
|
||||
|
||||
<script>
|
||||
function bounceBoat(elem) {
|
||||
|
||||
elem.onclick = null; // следующий клик не испортит анимацию
|
||||
|
||||
function go() {
|
||||
var marginLeft = parseInt(elem.style.marginLeft) || 0;
|
||||
|
||||
if (marginLeft == 0) {
|
||||
elem.className = 'bouncing-boat';
|
||||
} else {
|
||||
elem.className = 'bouncing-boat flip-horizontal';
|
||||
}
|
||||
|
||||
elem.style.marginLeft = (marginLeft ? 0 : 400) + 'px';
|
||||
|
||||
}
|
||||
|
||||
go();
|
||||
|
||||
elem.addEventListener('transitionend', go); /* на будущее */
|
||||
elem.addEventListener('webkitTransitionEnd', go);
|
||||
elem.addEventListener('mozTransitionEnd', go);
|
||||
elem.addEventListener('oTransitionEnd', go);
|
||||
elem.addEventListener('msTransitionEnd', go);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
5-animation/2-css-transitions/ease-in-out.png
Normal file
BIN
5-animation/2-css-transitions/ease-in-out.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
5-animation/2-css-transitions/ease-in.png
Normal file
BIN
5-animation/2-css-transitions/ease-in.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
5-animation/2-css-transitions/ease-out.png
Normal file
BIN
5-animation/2-css-transitions/ease-out.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
5-animation/2-css-transitions/ease.png
Normal file
BIN
5-animation/2-css-transitions/ease.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
5-animation/2-css-transitions/train-curve.png
Normal file
BIN
5-animation/2-css-transitions/train-curve.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Loading…
Add table
Add a link
Reference in a new issue