It's interesting comparing how it came out in each of the browsers:
- Safari felt like it was really struggling to handle it,
- Chrome was drawing the circles a bit choppy due to the floating point positions,
- Firefox was really nice and smooth, and
- Opera was good but not quite as good as Firefox.
Demo
Markup
<div id="working-container"> <div class="working"> <div class="ball"></div> <div class="ball"></div> <div class="ball"></div> <div class="ball"></div> <div class="ball"></div> </div> </div>
The
.working needs to be added after the .ball elements are loaded otherwise the timing will be wrong.CSS
I took out all the vendor-prefixes for simplicity, the SASS below has them included.
#working-container {
position:relative;
background-color:#2d2d2d;
width:300px;
height:200px;
margin:20px auto;
}
.working {
position:absolute;
top:50%;
left:50%;
}
.working .ball {
position: absolute;
background-color: #0D76BD;
width: 5px;
height: 5px;
border-radius: 2.5px;
opacity: 0;
animation-name: working;
animation-duration: 4.6s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.working .ball:nth-child(1) {
animation-delay: 0s;
}
.working .ball:nth-child(2) {
animation-delay: 0.4s;
}
.working .ball:nth-child(3) {
animation-delay: 0.8s;
}
.working .ball:nth-child(4) {
-moz-animation-delay: 1.2s;
}
.working .ball:nth-child(5) {
animation-delay: 1.6s;
}
@keyframes working {
0% {
left: -85px;
opacity: 0;
}
3.261% {
left: -55px;
}
6.522% {
left: -35px;
opacity: 1;
}
9.783% {
left: -20px;
}
32.609% {
left: 0px;
}
55.435% {
left: 20px;
}
58.696% {
left: 35px;
opacity: 1;
}
61.957% {
left: 55px;
}
65.217%, 100% {
left: 85px;
opacity: 0;
}
}
SASS
$number-of-balls:5;
$ball-delay:0.4;
$duration:3s;
$gap:($number-of-balls - 1) * $ball-delay;
$duration-percentage:$duration / ($duration + $gap);
#working-container {
position:relative;
background-color:#2d2d2d;
width:300px;
height:200px;
margin:20px auto;
}
.working {
position:absolute;
top:50%;
left:50%;
}
.working .ball {
position:absolute;
background-color:#0D76BD;
width:5px;
height:5px;
border-radius:2.5px;
opacity:0;
-moz-animation-name: working;
-moz-animation-duration: $duration + $gap;
-moz-animation-iteration-count: infinite;
-moz-animation-timing-function: linear;
-o-animation-name: working;
-o-animation-duration: $duration + $gap;
-o-animation-iteration-count: infinite;
-o-animation-timing-function: linear;
-webkit-animation-name: working;
-webkit-animation-duration: $duration + $gap;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
@mixin initial-delay($n) {
$delay:unquote(($n - 1) * $ball-delay + 's');
-moz-animation-delay:$delay;
-o-animation-delay:$delay;
-webkit-animation-delay:$delay;
}
.working .ball:nth-child(1) { @include initial-delay(1); }
.working .ball:nth-child(2) { @include initial-delay(2); }
.working .ball:nth-child(3) { @include initial-delay(3); }
.working .ball:nth-child(4) { @include initial-delay(4); }
.working .ball:nth-child(5) { @include initial-delay(5); }
@-moz-keyframes working {
0% {
left:-85px;
opacity:0;
}
#{5 * $duration-percentage + '%'} {
left:-55px;
}
#{10 * $duration-percentage + '%'} {
left:-35px;
opacity:1;
}
#{15 * $duration-percentage + '%'} {
left:-20px;
}
#{50 * $duration-percentage + '%'} {
left:0px;
}
#{85 * $duration-percentage + '%'} {
left:20px;
}
#{90 * $duration-percentage + '%'} {
left:35px;
opacity:1;
}
#{95 * $duration-percentage + '%'} {
left:55px;
}
#{100 * $duration-percentage + '%'}, 100% {
left:85px;
opacity:0;
}
}
@-o-keyframes working {
0% {
left:-85px;
opacity:0;
}
#{5 * $duration-percentage + '%'} {
left:-55px;
}
#{10 * $duration-percentage + '%'} {
left:-35px;
opacity:1;
}
#{15 * $duration-percentage + '%'} {
left:-20px;
}
#{50 * $duration-percentage + '%'} {
left:0px;
}
#{85 * $duration-percentage + '%'} {
left:20px;
}
#{90 * $duration-percentage + '%'} {
left:35px;
opacity:1;
}
#{95 * $duration-percentage + '%'} {
left:55px;
}
#{100 * $duration-percentage + '%'}, 100% {
left:85px;
opacity:0;
}
}
@-webkit-keyframes working {
0% {
left:-85px;
opacity:0;
}
#{5 * $duration-percentage + '%'} {
left:-55px;
}
#{10 * $duration-percentage + '%'} {
left:-35px;
opacity:1;
}
#{15 * $duration-percentage + '%'} {
left:-20px;
}
#{50 * $duration-percentage + '%'} {
left:0px;
}
#{85 * $duration-percentage + '%'} {
left:20px;
}
#{90 * $duration-percentage + '%'} {
left:35px;
opacity:1;
}
#{95 * $duration-percentage + '%'} {
left:55px;
}
#{100 * $duration-percentage + '%'}, 100% {
left:85px;
opacity:0;
}
}