Подобные индикаторы загрузки можно встретить на многих flash-сайтах. Но можно реализовать такое и с помощью CSS.
HTML
Необходимо три HTML-элемента:
- spinner — полукруг, который вращается постоянно
- mask — элемент, скрывающий spinner в течение первой половины анимации
- filler — элемент, завершающий вторую половину анимации
spinner и filler — две половины нашего круга, поэтому применяем к ним класс .pie
<div class="wrapper">
<div class="spinner pie"></div>
<div class="filler pie"></div>
<div class="mask"></div>
</div>
CSS
Устанавливаем размеры контейнера:
.wrapper {
width: 250px;
height: 250px;
position: relative;
background: white;
}
CSS для spinner и filler. Ширина каждого равна 50%, т.к. они являются двумя частями одного круга:
.pie {
width: 50%;
height: 100%;
position: absolute;
background: #08C;
border: 10px solid rgba(0,0,0,0.4);
}
Spinner должен отображаться как полукруг, кроме этого, с помощью z-index необходимо расположить его поверх filler, но под mask. Еще добавляем анимацию:
.spinner {
border-radius: 125px 0 0 125px;
z-index: 200;
border-right: none;
animation: rota 10s linear infinite;
}
Filler является второй половиной прогресс-бара, поэтому устанавливаем для анимации steps(1, end) и прозрачность 0:
.filler {
border-radius: 0 125px 125px 0;
z-index: 100;
border-left: none;
animation: fill 10s steps(1, end) infinite;
left: 50%;
opacity: 0;
}
Mask присутствует с начала анимации, поэтому прозрачность равна 1, фон наследуется, а чтобы быть поверх spinner'а, z-index равен 300:
.mask {
width: 50%;
height: 100%;
position: absolute;
z-index: 300;
opacity: 1;
background: inherit;
animation: mask 10s steps(1, end) infinite;
}
Первая анимация rota — для spinner'а: вращение на 360° за 10 секунд.
Вторая анимация fill — для filler'а: меняется прозрачность с 0 на 1 через 5 секунд.
Вторая анимация mask — для mask'а: меняется прозрачность с 1 на 0 через 5 секунд.
@keyframes rota {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fill {
0% { opacity: 0; }
50%, 100% { opacity: 1; }
}
@keyframes mask {
0% { opacity: 1; }
50%, 100% { opacity: 0; }
}
Анимация по этапам:
- spinner находится слева, скрыт маской, filler скрыт
- spinner начинает поворачиваться и появляться из-за маски
- spinner проходит 72° и продолжает поворачиваться
- spinner проходит 108° и продолжает поворачиваться
- spinner проходит 144° и продолжает поворачиваться
- spinner проходит 180° и продолжает поворачиваться. В этот момент filler становится видимым, а mask исчезает
- spinner проходит 216° и продолжает поворачиваться
- spinner проходит 252° и продолжает поворачиваться
- spinner проходит 288° и продолжает поворачиваться
- spinner проходит 324° и продолжает поворачиваться
- spinner проходит 360° и возвращается в начальную точку. В этот момент mask становится видимым, а filler исчезает
Бонусы
Пауза при наведении на прогресс-бар:
.wrapper:hover .filler,
.wrapper:hover .spinner,
.wrapper:hover .mask {
animation-play-state: paused;
}
С помощью z-index можно легко добавить текст, который будет вращаться вместе со spinner'ом:
.spinner:after {
content: "";
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
top: 10px;
right: 10px;
background: #fff;
border: 1px solid rgba(0,0,0,0.4);
box-shadow: inset 0 0 3px rgba(0,0,0,0.2);
}
CSS переменные
Для удобства можно использовать переменные, например устанавливать время анимации:
.animation-duration {
animation-duration: 10s;
}
<div class="wrapper">
<div class="spinner pie animation-duration"></div>
<div class="filler pie animation-duration"></div>
<div class="mask animation-duration"></div>
</div>
Минусы
В подобной реализации анимации есть и минусы:
- Нет поддержки градиентов.
- Нет поддержки box-shadow.
- Неадаптивно. При изменении размеров родительского контейнера необходимо вручную менять border-radius.
- Несемантично (4 элемента для одной анимации).
Поддержка браузерами
- Internet Explorer 10
- Firefox 12+
- Chrome
- Safari 5+
- Opera 12+
- iOS Safari 3+
- Android 2+ (buggy till v4)
Демонстрация
Автор: grokru
Спасибо конечно за труды но Вы сами пробовали скопировать и вставить то что написали, а потом запустить, скажем в Хроме(я говорю про часть до бонусов)? Зрелище устрашающее. А все потому, что Вы используете border вываливающий за пределы родительских элементов(и не только их, а еще и масок), а еще все эти кубики(spinner, кажется), крутятся вокруг своей оси, а должны крутится по оси своей правой стороны, звучит сложно, поэтому можно просто вставить это transform-origin: 100% 50%;