Анимация в CSS3. Часть I

Автор: Татьяна Шкабко, Александр Головко Дата публикации: 06.10.2010
Последнее обновление:12.09.2017

Чаще всего масштабные анимации на сайтах делаются с помощью технологии Flash. Для более мелких эффектов, например таких, как эффект выпадающего окошка, используется JavaScript. Я использую для этого любимую библиотеку jQuery и ее функцию animate. Ее работа меня вполне устраивает.

Но новое время предоставляет новые возможности. Safari 4+ и Chrome 3+ уже сейчас поддерживают возможность задать анимационные эффекты на странице с помощью CSS3. Рано или поздно остальные браузеры тоже поддержат эту инициативу. Чтобы не отстать от жизни, верстальщик должен знать CSS3 свойства, которые отвечают за CSS анимацию, и уметь задавать разнообразные анимационные эффекты элементам, не используя JavaScript.

Итак, начнем.

Теоретические сведения

Для задания CSS3 анимации элементу используется CSS3 свойство animation. Это свойство — сокращенная запись различных свойств анимации:

В прямом виде эти CSS3 свойства не поддерживает ни один из распространенных браузеров, но Safari 4+ и Chrome 3+ уже сейчас поддерживают эти свойства с вендорным префиксом -webkit-:

Имя анимации и список анимированных переходов для этого имени задается с помощью CSS3 правила @keyframes. Для Safari 4+ и Chrome 3+ используется @-webkit-keyframes.

Как это выглядит на практике

Анимация в CSS3 представляет собой плавное изменение значения какого-либо свойства. Рассмотрим простейший анимационный эффект: перемещение блока. Здесь и далее используем помимо CSS3 также рабочий вариант свойств с префиксом -webkit-.

div {
	position: relative;
	top: 50px;
	left: 0px;
	-webkit-animation-name: 'movement';
	-webkit-animation-duration: 10s;
	animation-name: 'movement';
	animation-duration: 10s;
}
@-webkit-keyframes 'movement' {
    from {
	top: 50px;
	left: 0px;
    }
    50% {
	top: 150px;
	left: 100px;
    }
    to {
	top: 400px;
	left: 300px;
    }	
}
@keyframes 'movement' {
    from {
	top: 50px;
	left: 0px;
    }
    50% {
	top: 150px;
	left: 100px;
    }
    to {
	top: 400px;
	left: 300px;
    }	
}

Счастливые обладатели Safari 4+ и Chrome 3+ могут увидеть это на демо-примере. Для остальных поясняю, что произойдет.

Тут описана анимация перемещения (изменение координат блока с течением времени). В данном примере анимация состоит из 3-х кадров, но количество ключевых кадров может быть любым. В первый момент анимации, описываемый селектором кадра from, координаты блока top: 50px, left: 0px. Следующий ключевой кадр описывает значения свойств через 50% времени анимации, задаваемой свойством animation-duration (-webkit-animation-duration). В данном примере 50% от 10с это 5 секунд. Т.е. через 5с координаты блока станут top: 150px, left: 100px. В последний момент времени, описываемый селектором кадра to (через 10с), блок получит абсолютные координаты top: 400px, left: 300px.

Замечание! Анимация происходит не в три рывка, а плавно.

Каким образом достигается плавность анимации?

Для достижения этой плавности рассчитываются промежуточные значения между ключевыми кадрами. Значения интерполируются в зависимости, описанной некоторой кривой Безье третьего порядка. Выбрать наиболее подходящий вариант кривой для интерполяции можно с помощью свойства animation-timing-function (-webkit-animation-timing-function).

Значение свойства animation-timing-function (-webkit-animation-timing-function) может быть как одинаковым для всех переходов анимации, так и разным для разных переходов между разными ключевыми кадрами. В первом случае свойство и значение указываются для элемента вместе с остальными свойствами анимации, а во втором случае они указываются при описании того ключевого кадра, вслед за которым будет идти описываемый переход. Можно также задать их одновременно:

div {
	position:relative;
	top: 50px;
	left: 0px;
	-webkit-animation-name: 'movement';
	-webkit-animation-duration: 10s;
	-webkit-animation-timing-function: easy-out;
	animation-name: 'movement';
	animation-duration: 10s;
	animation-timing-function: easy-out;
}
@-webkit-keyframes 'movement' {
    from {
	top: 50px;
	left: 0px;
	-webkit-animation-timing-function: easy-in-out;
    }
    50% {
	top: 150px;
	left: 100px;
    }
    to {
	top: 400px;
	left: 300px;
    }	
}
@keyframes 'movement' {
    from {
	top: 50px;
	left: 0px;
	-webkit-animation-timing-function: easy-in-out;
    }
    50% {
	top: 150px;
	left: 100px;
    }
    to {
	top: 400px;
	left: 300px;
    }	
}

Между первым и вторым ключевым кадром будет применено значение easy-in-out, а к оставшемуся промежутку между вторым и третьим кадром будет применено значение easy-out.

Обязательно ли совпадение начальных значений анимируемых свойств и значений анимируемых свойств для первого кадра анимации?

Нет, не обязательно. Если начальные значения и значения первого кадра не совпадают, то начальных значений можно и не увидеть, если у анимации нет задержки. Если задержка есть, то во время задержки будет видно начальные значения, а потом произойдет резкий рывок к первому кадру анимации. Чтобы в течение задержки было видно первый кадр, а не начальные значения, можно использовать -webkit-animation-fill-mode со значением backwards. Это свойство поддерживает Safari 5 и Chrome 4. Это же свойство со значением forwards дает возможность видеть эффект от анимации, когда та уже закончила проигрываться (после завершения анимации элемент получает не начальные значения, а какие-то промежуточные из анимации). Наглядно разницу можно посмотреть в демо-примере (смотреть Safari 5+, Chrome 4+).

Может ли какое-то свойство элемента отсутствовать в CSS правиле для этого элемента, но появляться в момент описания анимации?

Может, но только при условии, что значение по умолчанию этого свойства можно анимировать (т.е. в принципе существует несколько промежуточных значений между начальным и конечным значением). Рассмотрим пример:

div {
	position: relative;
	-webkit-animation-name: 'movement';
	-webkit-animation-duration: 10s;
	animation-name: 'movement';
	animation-duration: 10s;
}
@-webkit-keyframes 'movement' {
    from {
	top: 50px;
	left: 0px;
    }
    50% {
	top: 150px;
	left: 100px;
    }
    to {
	top: 400px;
	left: 300px;
    }	
}
@keyframes 'movement' {
    from {
	top: 50px;
	left: 0px;
    }
    50% {
	top: 150px;
	left: 100px;
    }
    to {
	top: 400px;
	left: 300px;
    }	
}

Так можно делать, поскольку координаты элемента в этом случае по умолчанию заданы top: 0px; left: 0px.

А так делать нельзя:

div {
	-webkit-animation-name: 'bordered';
	-webkit-animation-duration: 10s;
	animation-name: 'bordered';
	animation-duration: 10s;
}
@-webkit-keyframes 'bordered' {
    from {
	border: 1px dashed #0f0;
    }
    to {
	border: 5px dashed #f00;
    }	
}
@keyframes 'bordered' {
    from {
	border: 1px dashed #0f0;
    }
    to {
	border: 5px dashed #f00;
    }	
}

Свойство border-style анимировать нельзя (какое, например, значение border-style может быть промежуточным между solid и dashed?), а в этом примере получается, что оно меняет свое значение со значения по умолчанию none на значение анимации dashed.

Правильно будет сначала описать border-style для самого элемента:

div {
	border-style: dashed;
	border-width: 0px;
	-webkit-animation-name: 'bordered';
	-webkit-animation-duration: 10s;
	animation-name: 'bordered';
	animation-duration: 10s;
}
@-webkit-keyframes 'bordered' {
    from {
	border-width: 1px;
	border-color: #0f0;
    }
    to {
	border-width: 5px;
	border-color: #f00;
    }	
}
@keyframes 'bordered' {
    from {
	border-width: 1px;
	border-color: #0f0;
    }
    to {
	border-width: 5px;
	border-color: #f00;
    }	
}

Также можно сделать так:

div {
	border-style: dashed;
	border-width: 0px;
	-webkit-animation-name: 'bordered';
	-webkit-animation-duration: 10s;
	animation-name: 'bordered';
	animation-duration: 10s;
}
@-webkit-keyframes 'bordered' {
    from {
	border: 1px dashed #0f0;
    }
    to {
	border: 5px dashed #f00;
    }	
}
@keyframes 'bordered' {
    from {
	border: 1px dashed #0f0;
    }
    to {
	border: 5px dashed #f00;
    }	
}

Сравнить все 3 примера вживую можно в демонстрационном примере.

Продолжение читайте в статье Анимация в CSS3. Часть II.

Материалы