Here is my idea where I will only rely on CSS and few element. I will detail each part alone then I will combine this into one animation.
For the icon part (the star) I would do the same but I will probably consider a grayscale
filter to have a generic effect that work with any element and any color.
.magic i{
color:red;
filter:grayscale(100%);
}
.magic:hover i{
animation:change 1s forwards;
}
@keyframes change{
50% {
transform:scale(0);
filter:grayscale(100%);
}
51% {
filter:grayscale(0%);
}
100% {
transform:scale(1);
filter:grayscale(0%);
}
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
<span class="magic">
<i class="fas fa-star fa-5x"></i>
</span>
For the circle I will consider only one element and the trick here is to rely on border coloration vs background coloration. We initially make the height/width to be 0
and we only have border thus it will be a full circle. Then we simply decrease the thickness of border while keeping the overall width the same. So we will do:
- Start form width/height
0
and border-width 0
- We increase border-width to create the scale effect
- We decrease the border-width while increasing width/height to keep the overall width/height the same.
.circle {
display:inline-block;
width:0px;
height:0px;
border-radius:50%;
border-color:orange;
border-style:solid;
border-width:0px;
box-sizing:border-box;
}
body:hover .circle {
animation:change 1s forwards;
}
@keyframes change {
50% {
border-width:25px;
}
100% {
border-width:0;
width:50px;
height:50px;
}
}
body {
min-height:100px;
}
<span class="circle"></span>
This solution has a small drawback as it will make the element to increase from the top left and not the center. We can correct this by using scale instead of changing width/height:
.circle {
display:inline-block;
width:50px;
height:50px;
border-radius:50%;
border-color:orange;
border-style:solid;
border-width:25px;
transform:scale(0);
box-sizing:border-box;
}
body:hover .circle {
animation:change 1s linear forwards;
}
@keyframes change {
50% {
transform:scale(1);
border-width:25px;
}
100% {
transform:scale(1);
border-width:0;
}
}
body {
min-height:100px;
}
<span class="circle"></span>
We can still simplify considering a simple transition:
.circle {
display:inline-block;
width:50px;
height:50px;
border-radius:50%;
border-color:orange;
border-style:solid;
border-width:25px;
transform:scale(0);
box-sizing:border-box;
transition:
transform 0.5s,
border-width 0.5s 0.5s;
}
body:hover .circle {
border-width:0;
transform:scale(1);
}
body {
min-height:100px;
}
<span class="circle"></span>
Now the tricky part and the small circles. For this I will rely on radial-gradient
and scale. the idea is to create the small circles with gradient inside one element and using scale we will create the expanding effect.
.small {
display:inline-block;
width:100px;
height:100px;
background:
/*4 reds*/
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
/*4 oranges*/
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%);
background-size:16px 16px;
background-position:
calc(50% - 30px) calc(50% - 30px),
calc(50% + 30px) calc(50% - 30px),
calc(50% - 30px) calc(50% + 30px),
calc(50% + 30px) calc(50% + 30px),
calc(50% + 0px) calc(50% + 40px),
calc(50% + 40px) calc(50% + 0px),
calc(50% - 40px) calc(50% + 0px),
calc(50% + 0px) calc(50% - 40px);
background-repeat:no-repeat;
border-radius:50%;
}
<span class="small"></span>
I have created 8 circles and placed them by offseting from the center (check this answer to get more details about how background-position
works: https://stackoverflow.com/a/51734530/8620333). You simply need to adjust the size, position and color of the circle like you want.
And here is with animation:
.small {
display:inline-block;
width:100px;
height:100px;
background:
/*4 reds*/
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
/*4 oranges*/
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%);
background-size:16px 16px;
background-position:
calc(50% - 30px) calc(50% - 30px),
calc(50% + 30px) calc(50% - 30px),
calc(50% - 30px) calc(50% + 30px),
calc(50% + 30px) calc(50% + 30px),
calc(50% + 0px) calc(50% + 40px),
calc(50% + 40px) calc(50% + 0px),
calc(50% - 40px) calc(50% + 0px),
calc(50% + 0px) calc(50% - 40px);
background-repeat:no-repeat;
border-radius:50%;
transform:scale(0);
transition:transform 0.5s,opacity 0.4s 0.4s;
}
body {
min-height:200px;
}
body:hover .small {
transform:scale(1);
opacity:0;
}
<span class="small"></span>
If you want a more accurate animation you can also consider decreasing the circles by reducing the background-size
.
.small {
display:inline-block;
width:100px;
height:100px;
background:
/*4 reds*/
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
/*4 oranges*/
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%);
background-size:16px 16px; /*at least 2x7px */
background-position:
calc(50% - 30px) calc(50% - 30px),
calc(50% + 30px) calc(50% - 30px),
calc(50% - 30px) calc(50% + 30px),
calc(50% + 30px) calc(50% + 30px),
calc(50% + 0px) calc(50% + 40px),
calc(50% + 40px) calc(50% + 0px),
calc(50% - 40px) calc(50% + 0px),
calc(50% + 0px) calc(50% - 40px);
background-repeat:no-repeat;
border-radius:50%;
transform:scale(0);
transition:transform 0.5s,opacity 0.4s 0.4s,background-size 0.5s 0.4s;
}
body {
min-height:200px;
}
body:hover .small {
transform:scale(1);
opacity:0;
background-size:0 0;
}
<span class="small"></span>
Now you simply do the same with the other small circles by changing some of the values.
Let's put all this together!
.magic {
display:inline-block;
margin:50px;
position:relative;
}
.magic i{
color:orange;
filter:grayscale(100%);
position:relative;
}
.magic:hover i{
animation:change 1s forwards;
}
@keyframes change{
50% {
transform:scale(0);
filter:grayscale(100%);
}
51% {
filter:grayscale(0%);
}
100% {
transform:scale(1);
filter:grayscale(0%);
}
}
/**/
.magic:before {
content:"";
position:absolute;
top:calc(50% - 45px);
left:calc(50% - 45px);
width:90px;
height:90px;
border-radius:50%;
border-color:orange;
border-style:solid;
border-width:45px;
transform:scale(0);
box-sizing:border-box;
}
.magic:hover::before {
transition:
transform 0.5s,
border-width 0.5s 0.5s;
border-width:0;
transform:scale(1);
}
/**/
.magic::after {
content:"";
position:absolute;
width:160px;
height:160px;
left:calc(50% - 80px);
top:calc(50% - 80px);
background:
/*4 reds*/
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
/*4 oranges*/
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%);
background-size:16px 16px;
background-position:
calc(50% - 50px) calc(50% - 50px),
calc(50% + 50px) calc(50% - 50px),
calc(50% - 50px) calc(50% + 50px),
calc(50% + 50px) calc(50% + 50px),
calc(50% + 0px) calc(50% + 70px),
calc(50% + 70px) calc(50% + 0px),
calc(50% - 70px) calc(50% + 0px),
calc(50% + 0px) calc(50% - 70px);
background-repeat:no-repeat;
border-radius:50%;
transform:scale(0);
}
.magic:hover:after {
transform:scale(1);
opacity:0;
background-size:0 0;
transition:
transform 0.5s 0.5s,
opacity 0.4s 0.9s,
background-size 0.5s 0.9s;
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
<span class="magic">
<i class="fas fa-star fa-5x"></i>
</span>
<span class="magic">
<i class="fas fa-user fa-5x"></i>
</span>
As I said, it's not perfect but very close to what you want with less of element and with the needed details so you can easily adjust the different values. It's also easy to use with any icon since you only have to add a wrapper to your icon.
I didn't add the tiny circles for simplicity but we can consider another pseudo element and easily add them:
.magic {
display:inline-block;
margin:50px;
position:relative;
}
.magic i{
color:orange;
filter:grayscale(100%);
}
.magic:hover i{
animation:change 1s forwards;
}
@keyframes change{
50% {
transform:scale(0);
filter:grayscale(100%);
}
51% {
filter:grayscale(0%);
}
100% {
transform:scale(1);
filter:grayscale(0%);
}
}
/**/
.magic:before {
content:"";
position:absolute;
top:calc(50% - 45px);
left:calc(50% - 45px);
width:90px;
height:90px;
border-radius:50%;
border-color:orange;
border-style:solid;
border-width:45px;
transform:scale(0);
box-sizing:border-box;
}
.magic:hover::before {
border-width:0;
transform:scale(1);
transition:
transform 0.5s,
border-width 0.5s 0.5s;
}
/**/
.magic::after,
.magic i::after{
content:"";
position:absolute;
width:160px;
height:160px;
left:calc(50% - 80px);
top:calc(50% - 80px);
background:
/*4 reds*/
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
radial-gradient(circle,red 50%,transparent 60%),
/*4 oranges*/
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%),
radial-gradient(circle,orange 50%,transparent 60%);
background-size:16px 16px;
background-position:
calc(50% - 50px) calc(50% - 50px),
calc(50% + 50px) calc(50% - 50px),
calc(50% - 50px) calc(50% + 50px),
calc(50% + 50px) calc(50% + 50px),
calc(50% + 0px) calc(50% + 70px),
calc(50% + 70px) calc(50% + 0px),
calc(50% - 70px) calc(50% + 0px),
calc(50% + 0px) calc(50% - 70px);
background-repeat:no-repeat;
border-radius:50%;
transform:scale(0);
}
.magic i::after {
background-size:10px 10px;
transform:rotate(10deg) scale(0);
}
.magic:hover:after {
transform:scale(1);
opacity:0;
background-size:0 0;
transition:transform 0.5s 0.5s,opacity 0.4s 0.9s,background-size 0.5s 0.9s;
}
.magic:hover i:after {
transform:rotate(10deg) scale(1);
opacity:0;
background-size:0 0;
transition:transform 0.5s 0.5s,opacity 0.4s 0.9s,background-size 0.5s 0.9s;
}
/**/
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
<span class="magic">
<i class="fas fa-star fa-5x"></i>
</span>
<span class="magic">
<i class="fas fa-user fa-5x"></i>
</span>
UPDATE
Here is an improvement of the code considering some CSS variable and using more flexbile unit to easily control the dimension:
.magic {
display:inline-block;
margin:50px;
position:relative;
--r:45px;
}
.magic i{
color:orange;
filter:grayscale(100%);
}
.magic:hover i{
animation:change 1s forwards;
}
@keyframes change{
50% {
transform:scale(0);
filter:grayscale(100%);
}
51% {
filter:grayscale(0%);
}
100% {
transform:scale(1);
filter:grayscale(0%);
}
}
/**/
.magic:before {
content:"";
position:absolute;
top:calc(50% - var(--r));
left:calc(50% - var(--r));
width:calc(2*var(--r));
height:calc(2*var(--r));
border-radius:50%;
border:solid orange var(--r);
transform:scale(0);
box-sizing:border-box;
}
.magic:hover::before {
border-width:0;
transform:scale(1);
transition:
transform 0.5s,
border-width 0.5s 0.5s;
}
/**/
.magic::after,
.magic i::after{
content:"";
position:absolute;
width: calc(4*var(--r));
height:calc(4*var(--r));
left:calc(50% - 2*var(--r));
top: calc(50% - 2*var(--r));
--c1:radial-gradient(circle,red 50% ,transparent 60%);
--c2:radial-gradient(circle,orange 50%,transparent 60%);
background:
/*4 reds*/
var(--c1),var(--c1),var(--c1),var(--c1),
/*4 oranges*/
var(--c2),var(--c2),var(--c2),var(--c2);
background-size:calc(var(--r)/3) calc(var(--r)/3);
background-position:
calc(50% - var(--r)) calc(50% - var(--r)),
calc(50% + var(--r)) calc(50% - var(--r)),
calc(50% - var(--r)) calc(50% + var(--r)),
calc(50% + var(--r)) calc(50% + var(--r)),
calc(50% + 0px) calc(50% + var(--r)*1.414),
calc(50% + var(--r)*1.414) calc(50% + 0px),
calc(50% - var(--r)*1.414) calc(50% + 0px),
calc(50% + 0px) calc(50% - var(--r)*1.414);
background-repeat:no-repeat;
transform:scale(0);
}
.magic i::after {
background-size:calc(var(--r)/5) calc(var(--r)/5);
transform:rotate(55deg) scale(0);
}
.magic:hover:after {
transform:scale(1);
opacity:0;
background-size:0 0;
transition:
transform 0.5s 0.5s,
opacity 0.4s 0.9s,
background-size 0.5s 0.9s;
}
.magic:hover i:after {
transform:rotate(55deg) scale(1);
opacity:0;
background-size:0 0;
transition:
transform 0.5s 0.5s,
opacity 0.4s 0.9s,
background-size 0.5s 0.9s;
}
/**/
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
<span class="magic" style="--r:80px;">
<i class="fas fa-star fa-10x"></i>
</span>
<span class="magic">
<i class="fas fa-user fa-5x"></i>
</span>
<span class="magic" style="--r:20px;">
<i class="far fa-bell fa-3x"></i>
</span>
Basically the variable r
will define the radius of the whole shape and you can easily changing based on the size of your icon.
Here is a Codepen demo if you want to play with the code