// Init values $animation-duration : 3s !default; $second-circle-time-offset: .125s !default; // We need to adjust animation for each size. $stroke-map: ( default: 4.5, bold : 6.5, xbold : 15 ) !default; .loadingAnimation { // We need a different duration than each circle for the whole loader // to have an animation that seems visually "random", so here, duration +20% and ease. animation: loaderRotation #{$animation-duration * 1.2} ease-in-out infinite; will-change: transform; @keyframes loaderRotation { from { transform: rotate(0); } to { transform: rotate(360deg); } } &-circle { transform-origin: 50%; fill: none; stroke: currentColor; stroke-width: map-get($stroke-map, default); will-change: transform; animation: $animation-duration linear infinite; &:nth-of-type(1) { animation-name: loaderOrbitX; } &:nth-of-type(2) { animation-name: loaderOrbitY; animation-delay: $second-circle-time-offset; } } @each $name, $value in $stroke-map { @if $name != 'default' { &.is-#{$name} &-circle { stroke-width: $value; &:nth-of-type(1) { animation-name: #{'loaderOrbitX-' + $name}; } &:nth-of-type(2) { animation-name: #{'loaderOrbitY-' + $name}; } } } @each $axis in (X,Y) { @keyframes #{'loaderOrbit' + $axis + if($name == 'default', '', '-' + $name)} { from { transform: #{'rotate' + $axis + '(0)'}; stroke-width: $value; } 25% { stroke-width: $value * 2; } 50% { stroke-width: $value; } 75% { stroke-width: $value * 2; } to { transform: #{'rotate' + $axis + '(360deg)'}; stroke-width: $value; } } } } }