В этом уроке, мы разберемся как создавать различные эффекты анимации при помощи CSS3. Несколько важных моментов, прежде чем мы начнем:
Вы не увидите никаких префиксов в CSS фрагментах, но вы, конечно же, найдете их в ресурсных файлах.
Цель этого урока, это показать потенциал CSS, а особенно CSS3, поэтому рендеринг может быть изменен на-IE9. Если вы планируете поддерживать эти браузеры, не забудьте сделать резервные варианты.
Мы будем использовать box-model, где [width]= [element-width] + [padding]+ [borders]. Мы активируем их с следующим фрагментом:
*, *:before, *:after { box-sizing: border-box; }
CSS: За и Против
Каковы преимущества и недостатки чистого эффекта CSS “загрузки” и “предварительной загрузки”? Почему не JavaScript код, или даже старый добрый способ: анимированный GIF? Нет универсального ответа на этот вопрос, все будет зависеть от ситуации. Но позвольте нам дать вам некоторые идеи:
За:
- CSS легко редактируемый: вы можете быстро изменить длительность, скорость, цвет и т.д. вашей анимации
- CSS является “вектроным”: вы можете масштабировать его по своему усмотрению без потери качества
- CSS анимации быстрее, чем JS “анимации”, так как они используют родной двигатель браузера
- CSS анимации используют GPU ускорение: если у вас есть хорошее устройство, то тогда у вас будет очень быстрая и плавная анимация
Против:
- У CSS анимации нет полной поддержки браузера: IE9 и Opera Mini не понимают их
- CSS (pre) загрузчики могут включать объемные разметки
- CSS немогут активировать экшнс на нажатие мышкой и тд., в отличие от JS
Пример 1
Мы начнем с чего-нибудь простого. Наш ползунок бесконечно бегает в окне слева направо. “Движение” является очень важным, для того чтобы пользователь видел, что приложение/сайт действительно что-то делает.
Разметка
<div class="bar"> <i class="sphere"></i> </div>
CSS
Во-первых, нам нужно создать контейнер для сферы: bar. Чтобы сохранить пропорции и сделать призагрузчики масштабируемыми, мы использовали em единицы. Просто измените значение размера шрифта на обертке, для того чтобы все масштабировалось так, как вы хотите.
.demo-1 .bar { /* Size and position */ font-size: 20px; /* 1em */ width: 10em; height: 1em; position: relative; margin: 100px auto; /* Styles */ border-radius: .5em; /* Height/2 */ background: white; /* Fallback */ background: rgba(255,255,255,0.6); box-shadow: 0 0 0 .05em rgba(100,100,100,0.075), /* Subtle border */ 0 0 0 .25em rgba(0,0,0,0.1), /* Outter border */ inset 0 .1em .05em rgba(0,0,0,0.1), /* Inset shadow */ 0 .05em rgba(255,255,255,0.7); /* Slight reflection */ }
Давайте займёмся “Подождите”. Вы, наверное, заметили, что его нету в разметке: это потому, что это контент. На самом деле он должен быть в разметке в реальном случае, так как это важное содержание, а не только графический материал.
.demo-1 .bar:after { /* Content and position */ content: "Подождите."; position: absolute; left: 25%; top: 150%; /* Font styles */ font-family: 'Carrois Gothic', sans-serif; font-size: 1em; color: #555; text-shadow: 0 .05em rgba(255,255,255,0.7); }
Теперь давайте взглянем на сферу.
.demo-1 .sphere { /* Size */ display: block; width: 1em; height: 100%; /* Styles */ border-radius: 50%; background: linear-gradient(#eee, #ddd); box-shadow: inset 0 .15em .1em rgba(255,255,255,0.3), /* Top light */ inset 0 -.1em .15em rgba(0,0,0,0.15), /* Bottom shadow */ 0 0 .25em rgba(0,0,0,0.3); /* Outter shadow */ /* Animation */ animation: move 1.75s ease-in-out infinite alternate; }
Ключевые фреймы запускающие анимации:
@keyframes move { to { margin-left: 90%; } }
Пример 2
Теперь давайте продолжим с чем-то немного посложнее, но не слишком! Вращающаяся … мельница? :)
Разметка
Этот пример полностью основан на псевдо-элементе. Полностью. Нет необходимости в дополнительной разметке.
<div class="spinner"></div>
CSS
Во-первых, сам элемент. Мы использовали красный и бежевый, но вы можете выбрать любой понравившийся вам цвет. То же самое касается количества цветов, мы взяли два, но вы можете пойти с четырьмя, или только одним, или любым другим количеством.
.demo-2 .spinner { /* Size and position */ font-size: 100px; /* 1em */ width: 1em; height: 1em; position: relative; margin: 100px auto; /* Styles */ border-radius: 50%; background: #FF4F72; /* Fallback */ background: linear-gradient(#ea2d0e 50%, #fcd883 50%), /* First column */ linear-gradient(#fcd883 50%, #ea2d0e 50%); /* Second column */ background-position: 0 0, /* Position of 1st column */ 100% 0; /* Position of 2nd column */ background-size: 50% 100%; /* Contraction of "50% 100%, 50% 100%" */ background-repeat: no-repeat; box-shadow: inset 0 0 0 .12em rgba(0,0,0,0.2), /* Inner border */ 0 0 0 .12em rgba(255,255,255,0.1); /* Outter border */ opacity: 0.7; animation: rota 3s infinite alternate; }
Теперь, псевдо-элемент для внутреннего прозрачного белого круга.
.demo-2 .spinner:after { /* Size */ content: ""; width: 50%; height: 50%; /* Perfect centering */ position: absolute; top: 25%; left: 25%; /* Styles */ border: .12em solid rgba(255,255,255,0.3); border-radius: inherit; }
Анимация
@keyframes rota { 25% { transform: rotate(270deg); } 50% { transform: rotate( 90deg); } 75% { transform: rotate(360deg); } 100% { transform: rotate(180deg); } }
Пример 3
Теперь давайте рассмотрим что-то немного сложнее. Но не волнуйтесь, это действительно не так сложно.
Разметка
HTML для этого варианта не самый красивый. Поскольку мы не можем анимировать псевдо-элементы, мы должны использовать несколько элементов, чтобы это сделать. Мы выбрали списки (даже если они не очень семантические), но вы можете выбрать все, что захотите.
<ul class="spinner"> <li></li> <li></li> <li></li> <li></li> </ul>
CSS
Первое, что нужно сделать, это стилизовать сам список.
.demo-3 .spinner { /* Size and position */ font-size: 100px; /* 1em */ width: 1em; height: 1em; margin: 100px auto; position: relative; /* Styles */ list-style: none; border-radius: 50%; border: .01em solid rgba(150,150,150,0.1); /* Subtle white line circling the dots */ }
И общие свойства для всех элементов списка.
.demo-3 .spinner li { width: .2em; height: .2em; position: absolute; border-radius: 50%; }
А теперь, несколько объяснений о том, что грядет. При загрузке страницы, четыре точки не будут перекрывать друг друга, они расположены как стороны света: север, юг, восток, запад. Но, их центры вращения все в одном и том же месте – в точном центре спиннера.
.demo-3 .spinner li:nth-child(1) { background: #00C176; /* Blue */ top: 0; left: 50%; margin-left: -.1em; /* Width/2 */ transform-origin: 50% 250%; animation: rota 1.13s linear infinite, opa 3.67s ease-in-out infinite alternate; } .demo-3 .spinner li:nth-child(2) { background: #FF003C; /* Red */ top: 50%; right: 0; margin-top: -.1em; /* Height/2 */ transform-origin: -150% 50%; animation: rota 1.86s linear infinite, opa 4.29s ease-in-out infinite alternate; } .demo-3 .spinner li:nth-child(3) { background: #FABE28; /* Yellow */ bottom: 0; left: 50%; margin-left: -.1em; /* Width/2 */ transform-origin: 50% -150%; animation: rota 1.45s linear infinite, opa 5.12s ease-in-out infinite alternate; } .demo-3 .spinner li:nth-child(4) { background: #88C100; /* Green */ top: 50%; left 0; margin-top -.1em; /* Height/2 */ transform-origin: 250% 50%; animation: rota 1.72s linear infinite, opa 5.25s ease-in-out infinite alternate; }
Наконец, две анимации. Одна предназначена для вращения, а другая для прозрачности. Да, прозрачность здесь меняется тоже!
@keyframes rota { to { transform: rotate(360deg); } } @keyframes opa { 12.0% { opacity: 0.80; } 19.5% { opacity: 0.88; } 37.2% { opacity: 0.64; } 40.5% { opacity: 0.52; } 52.7% { opacity: 0.69; } 60.2% { opacity: 0.60; } 66.6% { opacity: 0.52; } 70.0% { opacity: 0.63; } 79.9% { opacity: 0.60; } 84.2% { opacity: 0.75; } 91.0% { opacity: 0.87; } }
Пример 4
Разметка
Довольно тяжелый случай, так как нам нужно обернуть каждую букву на спан. Также, нам нужна обертка для отмены вращения основного элемента.
<div class="wrapper"> <div class="inner"> <span>L</span> <span>o</span> <span>a</span> <span>d</span> <span>i</span> <span>n</span> <span>g</span> </div> </div>
CSS
Во-первых, у нас есть много вещей, которые нужно применить к основному элементу: размер, положение, шрифт, анимация и т.д.
.demo-4 .wrapper { /* Size and position */ font-size: 25px; /* 1em */ width: 8em; height: 8em; margin: 100px auto; position: relative; /* Styles */ border-radius: 50%; background: rgba(255,255,255,0.1); border: 1em dashed rgba(138,189,195,0.5); box-shadow: inset 0 0 2em rgba(255,255,255,0.3), 0 0 0 0.7em rgba(255,255,255,0.3); animation: rota 3.5s linear infinite; /* Font styles */ font-family: 'Racing Sans One', sans-serif; color: #444; text-align: center; text-transform: uppercase; text-shadow: 0 .04em rgba(255,255,255,0.9); line-height: 6em; }
Мы все еще должны создать внутренние колеса с псевдо-элементами.
.demo-4 .wrapper:before, .demo-4 .wrapper:after { content: ""; position: absolute; z-index: -1; border-radius: inherit; box-shadow: inset 0 0 2em rgba(255,255,255,0.3); border: 1em dashed; } .demo-4 .wrapper:before { border-color: rgba(138,189,195,0.2); top: 0; right: 0; bottom: 0; left: 0; } .demo-4 .wrapper:after { border-color: rgba(138,189,195,0.4); top: 1em; right: 1em; bottom: 1em; left: 1em; }
Теперь внутренние обертки и спаны. Обратите внимание, как мы используем “reverse” параметр на внутреннем контейнере для отмены вращения основного элемента.
.demo-4 .wrapper .inner { width: 100%; height: 100%; animation: rota 3.5s linear reverse infinite; } .demo-4 .wrapper span { display: inline-block; animation: placeholder 1.5s ease-out infinite; } .demo-4 .wrapper span:nth-child(1) { animation-name: loading-1; } .demo-4 .wrapper span:nth-child(2) { animation-name: loading-2; } .demo-4 .wrapper span:nth-child(3) { animation-name: loading-3; } .demo-4 .wrapper span:nth-child(4) { animation-name: loading-4; } .demo-4 .wrapper span:nth-child(5) { animation-name: loading-5; } .demo-4 .wrapper span:nth-child(6) { animation-name: loading-6; } .demo-4 .wrapper span:nth-child(7) { animation-name: loading-7; }
К сожалению, нам нужна одна анимация для каждой буквы, так как они должны идти с задержкой. Сначала мы думали об анимации с задержкой, но это свойство только делает задержку при первом запуске, а не при каждом, поэтому такой способ работать не будет.
@keyframes rota { to { transform: rotate(360deg); } } @keyframes loading-1 { 14.28% { opacity: 0.3; } } @keyframes loading-2 { 28.57% { opacity: 0.3; } } @keyframes loading-3 { 42.86% { opacity: 0.3; } } @keyframes loading-4 { 57.14% { opacity: 0.3; } } @keyframes loading-5 { 71.43% { opacity: 0.3; } } @keyframes loading-6 { 85.71% { opacity: 0.3; } } @keyframes loading-7 { 100% { opacity: 0.3; } }
Эти анимациии может быть немного сложно понять, поэтому давайте разберемся, каждая буква должна:
- Потерять немного непрозрачности
- Вернуться к полной непрозрачности
- Подождите, пока все остальные буквы сделают тоже самое
- Вернитесь к шагу 1 и повторите
Как конкретно это сделать:
- Вы посчитали количество букв в своем элементе. Наш демо насчитывает 7
- Вы разделили 100 (количество ключевых кадров, выраженных в %) на это число. В этом примере оно равно ~ 14,28
- Каждый 14,28 ключевой кадр, буква делает свое дело
- Готово
Как видите, все примеры достаточно просты в использовании.
Высоких конверсий!