
Making loader in the shape of infinity symbol (∞) using clip : rect()
*Best supported in Chrome
Create Background circles
<div class="infinity-loader"> <div class="bg"><!--background circles--> <div class="left-bg"></div> <div class="right-bg"></div> </div> </div>
/* width = height = 70px border-width = 10px */ .infinity-loader .bg div{ width: 70px;/* width */ height: 70px;/* width */ border: 10px solid #aaa;/* border-width solid #aaa */ box-sizing: border-box;/* so that its border won't increase its width*/ border-radius: 50%;/* to make the div round*/ }
Align them horizontally :
.infinity-loader{ position: fixed;/*We have to use it as we are using absolute positioning on its children and we will align it in the center of the page*/ } .infinity-loader .bg div{ /*..*/ position: absolute; } .infinity-loader .right-bg{ transform: translate(100%,0); }
Make their borders overlap at their contact points :
.infinity-loader .right-bg{ /*..*/ left: -10px;/* -border-width */ }
Align at center :
.infinity-loader{ /*..*/ left: 50%; top: 50%; transform: translate(-50%,-50%); /*yes, we have to define width and height, otherwise transformation won't work*/ width: 130px;/* 2 x width - border-width */ height: 70px;/* width */ }
Create foreground circles
First make top-left box in which our top-left circle will animate :
<div class="infinity-loader"> <!-- .. --> <div class="fg"><!--foreground circles--> <div class="top-left-rect"> <div></div> </div> </div> </div>
.infinity-loader .bg div, .infinity-loader > .fg > div > div{/*note this*/ /*no change below*/ width: 70px;/* width */ height: 70px;/* width */ border: 10px solid #aaa;/* border-width solid #aaa */ box-sizing: border-box;/* so that its border won't increase its width*/ border-radius: 50%;/* to make the div round*/ position: absolute; } /*..*/ .infinity-loader > .fg > div > div{ border-color: orangered; }
We only need half circle :
.infinity-loader > .fg > div > div{ border-color: orangered orangered transparent transparent; }
Set its initial state :
.infinity-loader > .fg > div > div{ /*..*/ transform: rotate(135deg); }
Lets animate that half circle :
/* width = height = 70px border-width = 10px time = 1s */ /*..*/ .infinity-loader > .fg > div > div{ /*..*/ animation: spin 1s linear infinite;/* spin time linear infinite */ } @keyframes spin { 100%{transform: rotate(495deg)}/* (360 + 135)deg */ }
Make it visible on the upper half portion only :
.infinity-loader > .fg > div{ clip: rect(0,70px,35px,0);/* 0, width, width/2, 0*/ position: absolute;/* required for using clip: rect() */ }
Create Bottom Right Circle
<div class="fg"><!--foreground circles--> <div class="top-left-rect"> <div></div> </div> <!-- add the following --> <div class="bottom-right-rect"> <div></div> </div> </div>
Align it with following CSS :
.infinity-loader > .fg > div > div{ /*..*/ position: static;/*add this otherwise transformation in its parent won't work as expect*/ } .infinity-loader > .fg > .bottom-right-rect{ left:-10px;/* -border-width */ transform: translateX(100%) scale(1,-1); }
We have to fix timings for continuity:
.infinity-loader > .fg > .bottom-right-rect > div{ animation-delay: .5s;/* time/2 */ }
But now top-left and bottom-right circles won’t give time for top-right and bottom-left circles to animate. They should pause for a duration to give other circles to animate :
.infinity-loader > .fg > .bottom-right-rect > div{ animation-delay: .25s;/* time/4, we have to change it as animation duration has been decreasesd by 50% */ } @keyframes spin { 50%,100%{transform: rotate(495deg)}/* (360 + 135)deg , 50% time is for animation and other 50% for pause*/ }
Create Top Right Circle
<div class="fg"><!--foreground circles--> <div class="top-left-rect"> <div></div> </div> <div class="bottom-right-rect"> <div></div> </div> <!-- add the following --> <div class="top-right-rect"> <div></div> </div> </div>
Align it :
.infinity-loader > .fg > .top-right-rect{ left:-10px;/* -border-width */ transform: translateX(100%) scale(-1,1); }
And yes, adjust the timings :
.infinity-loader > .fg > .top-right-rect > div{ animation-delay:.5s;/* (2 x time)/4 */ }
Create Bottom Left Circle
<div class="fg"><!--foreground circles--> <div class="top-left-rect"> <div></div> </div> <div class="bottom-right-rect"> <div></div> </div> <div class="top-right-rect"> <div></div> </div> <!-- add the following --> <div class="bottom-left-rect"> <div></div> </div> </div>
.infinity-loader > .fg > .bottom-left-rect{ transform: scale(-1); } .infinity-loader > .fg > .bottom-left-rect > div{ animation-delay: .75s;/* (3 x time)/4 */ }
Add glow
.infinity-loader > .fg { filter:drop-shadow(0 0 6px orangered); }
Whole code :
<div class="infinity-loader"> <div class="bg"><!--background circles--> <div class="left-bg"></div> <div class="right-bg"></div> </div> <div class="fg"><!--foreground circles--> <div class="top-left-rect"> <div></div> </div> <div class="bottom-right-rect"> <div></div> </div> <div class="top-right-rect"> <div></div> </div> <div class="bottom-left-rect"> <div></div> </div> </div> </div>
/* width = height = 70px border-width = 10px time = 1s */ .infinity-loader{ position: fixed;/*We have to use it as we are using absolute positioning on its children and we will align it in the center of the page*/ left: 50%; top: 50%; transform: translate(-50%,-50%); /*yes, we have to define width and height, otherwise transformation won't work*/ width: 130px;/* 2 x width - border-width */ height: 70px;/* width */ } .infinity-loader .bg div, .infinity-loader > .fg > div > div{ width: 70px;/* width */ height: 70px;/* width */ border: 10px solid #aaa;/* border-width solid #aaa */ box-sizing: border-box;/* so that its border won't increase its width*/ border-radius: 50%;/* to make the div round*/ position: absolute; } .infinity-loader .right-bg{ transform: translate(100%,0); left: -10px;/* -border-width */ } .infinity-loader > .fg > div > div{ border-color: orangered orangered transparent transparent; transform: rotate(135deg); animation: spin 1s linear infinite;/* spin time linear infinite */ position: static;/*add this otherwise transformation in its parent won't work as expect*/ } .infinity-loader > .fg > div{ clip: rect(0,70px,35px,0);/* 0, width, width/2, 0*/ position: absolute;/* required for using clip: rect() */ } .infinity-loader > .fg > .bottom-right-rect{ left:-10px;/* -border-width */ transform: translateX(100%) scale(1,-1); } .infinity-loader > .fg > .bottom-right-rect > div{ animation-delay: .25s;/* time/4 */ } .infinity-loader > .fg > .top-right-rect{ left:-10px;/* -border-width */ transform: translateX(100%) scale(-1,1); } .infinity-loader > .fg > .top-right-rect > div{ animation-delay:.5s;/* (2 x time)/4 */ } .infinity-loader > .fg > .bottom-left-rect{ transform: scale(-1); } .infinity-loader > .fg > .bottom-left-rect > div{ animation-delay: .75s;/* (3 x time)/4 */ } .infinity-loader > .fg { filter:drop-shadow(0 0 6px orangered); } @keyframes spin { 50%,100%{transform: rotate(495deg)}/* (360 + 135)deg*/ }
Code is also available here : https://codepen.io/zFunx/pen/VXmwbO. Useful links :
Issues :
- Glowing effect doesn’t work in Edge and IE
- Little mis-alignment in the circles in Firefox