Эффекты для анимации загрузки с помощью CSS
В этом уроке мы сделаем несколько интересных анимированных индикаторов загрузки с помощью чистого CSS.
Плюсы и минусы чистого CSS
В чем преимущество создания лоадеров на чистом CSS? Почему бы не использовать решение на JS или даже анимированную GIF? На этот вопрос нет однозначного ответа, все зависит от ситуации. Рассмотрим плюсы и минусы.
Плюсы:
- CSS легко изменить: вы можете легко изменить, продолжительность, скорость, цвет, да что угодно в вашей анимации
- CSS — «векторный»: вы можете масштабировать анимацию без потери качества
- CSS анимация быстрее JavaScript решений
- CSS анимация использует графический процессор: чем лучше железо — тем более быстрая и плавная картинка
- CSS анимацию легко «поставить на паузу» с помощью свойства animation-play-state
Минусы
- CSS анимацию поддерживают не все браузеры
С помощью Modernizr можно решить проблему и использовать CSS анимацию в браузерах, которые её поддерживают, а там где нет — использовать GIF.
Пример 1
Начнем с простого примера. Небольшая сфера будет бесконечно кататься туда-сюда :). Движение необходимо, чтобы показать пользователю, что приложение или сайт что-то делает.
HTML разметка
<div class="bar"> <i class="sphere"></i> </div>
Всего 2 тега, можно было и одним обойтись, но CSS код при этом стал бы гораздо сложнее.
CSS
Сначала создадим контейнер для сферы, по которому она будет кататься. Для контроля размеров мы будем использовать CSS единицу измерения em. Благодаря этому размеры легко будет изменить, просто поменяв font-size.
.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 */ }
Теперь поговорим о надписи «Please wait». Как вы заметили, её нет в разметке: она генерируется автоматически. В реальном случае, конечно, лучше сделать это с помощью разметки, но для демо мы её сгенерируем.
.demo-1 .bar:after { /* Content and position */ content: "Please wait."; 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); }
Если вы хотите сделать надпись разметкой, просто создайте дополнительный span и пропишите необходимый стиль. Теперь сфера:
.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%; } }
Элемент sphere
запускает анимацию move
и с периодичностью 1.75 сек повторяет её в обратную сторону.
Если вы хотите самостоятельно задавать положение сферы, то придется написать немного JavaScript.
Пример 2
Теперь сделаем что-нибудь по-сложнее.
HTML разметка
В этом примере мы будем использовать CSS псевдоэлементы, поэтому разметка стала еще меньше.
<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
Сделаем что-нибудь еще более затейливое :).
Разметка
На этот раз разметка немного больше. Т.к. анимировать псевдоэлементы нельзя — мы используем список.
<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); /* Линия по которой катаются круги */ }
И напишем общий стиль для элементов списка:
.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
HTML
Для этого примера нам придется каждую букву обернуть span’ом. Также нам понадобится контейнер (.wrapper), в котором будет располагаться внутренний элемент с буквами, что бы избежать его вращения.
<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
Сначала назначим свойства главному элементу: size, position, font-styles, animation и т.д.
.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; } }
Что здесь происходит:
- Делаем букву прозрачной
- Возвращаем непрозрачность
- Ждем пока со всеми буквами произойдет то же самое
- Повторяем процесс
Как это реализовано:
- Считаем количество букв. В нашем примере — 7.
- Делим 100 на это число. Получаем примерно 14.28.
- На каждые 14.28 кадра анимации буква меняет прозрачночть.
Пример 5
HTML разметка
Нам снова понадобится только один элемент.
<div class="pre-loader"></div>
CSS
Наш элемент — один из вращающихся кругов, остальные сделаны с помощью box-shadow.
.demo-5 .pre-loader { /* Size and position */ font-size: 30px; /* 1em */ width: 1em; height: 1em; position: relative; margin: 100px auto; /* Styles */ border-radius: 50%; background: #123456; transform-origin: 50% 250%; animation: blink 1s steps(1, start) infinite, /* Blink */ counter-clock 8s linear infinite; /* Rotation */ /* Dots, clockwise */ box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em #123456, 0em 4em #123456, -1em 3em #123456, -2em 2em #123456, -1em 1em #123456; }
Прозрачный квадрат поверх кругов:
.demo-5 .pre-loader:after { /* Size and position */ content: ""; width: 3em; height: 3em; position: absolute; left: -1em; top: 1em; /* Styles */ transform: rotate(45deg); background: white; /* Fallback */ background: rgba(255,255,255,0.6); }
И анимация. Рассмотрим как работает анимация blink:
- Теперь у нас 8 элементов, поэтому делим 100 на 8, получаем 12.5.
- Каждые 12.5 кадров круг становится немного прозрачным:
rgb(18,52,86)
— RGB код цвета #123456. - В начале сам элемент становится прозрачным.
@keyframes counter-clock { to { transform: rotate(-360deg); } } @keyframes blink { 12.5% { background: rgba(18,52,86,0.6); box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em #123456, 0em 4em #123456, -1em 3em #123456, -2em 2em #123456, -1em 1em #123456; } 25% { background: #123456; box-shadow: 1em 1em rgba(18,52,86,0.6), 2em 2em #123456, 1em 3em #123456, 0em 4em #123456, -1em 3em #123456, -2em 2em #123456, -1em 1em #123456; } 37.5% { background: #123456; box-shadow: 1em 1em #123456, 2em 2em rgba(18,52,86,0.6), 1em 3em #123456, 0em 4em #123456, -1em 3em #123456, -2em 2em #123456, -1em 1em #123456; } 50% { background: #123456; box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em rgba(18,52,86,0.6), 0em 4em #123456, -1em 3em #123456, -2em 2em #123456, -1em 1em #123456; } 62.5% { background: #123456; box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em #123456, 0em 4em rgba(18,52,86,0.6), -1em 3em #123456, -2em 2em #123456, -1em 1em #123456; } 75% { background: #123456; box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em #123456, 0em 4em #123456, -1em 3em rgba(18,52,86,0.6), -2em 2em #123456, -1em 1em #123456; } 87.5% { background: #123456; box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em #123456, 0em 4em #123456, -1em 3em #123456, -2em 2em rgba(18,52,86,0.6), -1em 1em #123456; } 100% { background: #123456; box-shadow: 1em 1em #123456, 2em 2em #123456, 1em 3em #123456, 0em 4em #123456, -1em 3em #123456, -2em 2em #123456, -1em 1em rgba(18,52,86,0.6); } }
Готово!
Нет комментариев