Using CSS:
Doing what you are looking for using a single element with pure CSS is going to be really tough (if not impossible). We can do it by using as many elements as the no. of spokes that are required. Position the spokes absolutely at a certain location and rotate by the required angles. Origin should be fixed at the bottom of the element so that they all converge into one point.
The animation itself can be achieved by using linear-gradient
and animating their position.
.firework {
position: absolute;
top: 100px;
left: 100px;
border-radius: 30%;
height: 64px;
width: 2px;
background: linear-gradient(to top, red, red);
background-repeat: no-repeat;
background-size: 100% 64px;
background-position: 0px -64px;
transform-origin: bottom;
animation: firework-0 1s 1;
}
.firework:nth-child(2){
transform: rotate(36deg)
}
.firework:nth-child(3){
transform: rotate(72deg)
}
.firework:nth-child(4){
transform: rotate(108deg)
}
.firework:nth-child(5){
transform: rotate(144deg)
}
.firework:nth-child(6){
transform: rotate(180deg)
}
.firework:nth-child(7){
transform: rotate(216deg)
}
.firework:nth-child(8){
transform: rotate(252deg)
}
.firework:nth-child(9){
transform: rotate(288deg)
}
.firework:nth-child(10){
transform: rotate(324deg)
}
@keyframes firework-0 {
0% {
background-position: 0px 64px;
}
50% {
background-position: 0px 0px;
}
100% {
background-position: 0px -64px;
}
}
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
Note: The no. of elements can be reduced greatly if pseudo-elements are used but I'll leave it to you.
Lines that don't meet at the center:
If you need them to not converge at a point and look like they are apart but placed around a circle then the animation becomes a bit more complex. It would require a gradient which is transparent for half of its size and colored for the other . By animating the background's size and position, the required effect can be achieved.
The calc
in background position is critical because it makes the gradient be positioned with respect to the bottom of the element and thus makes the animation work as expected.
.firework {
position: absolute;
top: 100px;
left: 100px;
border-radius: 30%;
height: 64px;
width: 2px;
background: linear-gradient(to top, transparent 32px, red 32px);
background-repeat: no-repeat;
background-size: 100% 64px;
background-position: 100% calc(100% - 32px);
transform-origin: bottom;
animation: firework-0 1s 1;
}
.firework:nth-child(2) {
transform: rotate(36deg)
}
.firework:nth-child(3) {
transform: rotate(72deg)
}
.firework:nth-child(4) {
transform: rotate(108deg)
}
.firework:nth-child(5) {
transform: rotate(144deg)
}
.firework:nth-child(6) {
transform: rotate(180deg)
}
.firework:nth-child(7) {
transform: rotate(216deg)
}
.firework:nth-child(8) {
transform: rotate(252deg)
}
.firework:nth-child(9) {
transform: rotate(288deg)
}
.firework:nth-child(10) {
transform: rotate(324deg)
}
@keyframes firework-0 {
0% {
background-size: 100% 32px;
background-position: 100% calc(100% - 0px);
}
50% {
background-size: 100% 64px;
background-position: 100% calc(100% - 0px);
}
100% {
background-size: 100% 32px;
background-position: 100% calc(100% - 32px);
}
}
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
<div class="firework"></div>
Using SVG:
For effects like this, my recommendation would be to use SVG as SVG is the correct tool for creating them. It is also fairly simple to create and maintain.
All that we need are 10 line
elements that draw a line from one point to another, give it a dashed fill and then animating the stroke-dashoffset
to get the required effect.
Lines meeting at a center:
For this effect, the lines have to be created such that the first coordinate (x,y) will be the center of the imaginary circle (32,32). For second coordinate, we should find points on the imaginary circle based on the angle of the line. The formula is described here.
Note: In SVG, 0 degree corresponds to 3 o'clock position.
svg{
width: 128px;
height: 128px;
}
line{
stroke: red;
animation: firework 1s 1;
stroke-dasharray: 32 32; /* radius radius */
stroke-dashoffset: -32; /* -radius */
}
@keyframes firework{
from{
stroke-dashoffset: 32; /* radius */
}
to{
stroke-dashoffset: -32; /* -radius */
}
}
<svg viewBox='0 0 64 64'>
<g>
<line x1='32' y1='32' x2='32' y2='0' />
<line x1='32' y1='32' x2='50.80' y2='6.11' />
<line x1='32' y1='32' x2='62.43' y2='22.11' />
<line x1='32' y1='32' x2='62.43' y2='41.88' />
<line x1='32' y1='32' x2='50.80' y2='57.88' />
<line x1='32' y1='32' x2='32' y2='64' />
<line x1='32' y1='32' x2='13.19' y2='57.88' />
<line x1='32' y1='32' x2='1.56' y2='41.88' />
<line x1='32' y1='32' x2='1.56' y2='22.11' />
<line x1='32' y1='32' x2='13.19' y2='6.11' />
</g>
</svg>
Lines that don't meet at center: (but their projections will)
For this effect, we should find points along two circles for the two coordinates. The first coordinate will be on an inner circle whose radius is smaller than the first (16 in this demo). The second will be on the larger circle (radius = 32 in this demo).
svg{
width: 128px;
height: 128px;
}
line{
stroke: red;
animation: firework 1s 1;
stroke-dasharray: 16 16; /* length of the line length of the line */
stroke-dashoffset: -16; /* -length */
}
@keyframes firework{
from{
stroke-dashoffset: 16; /* length */
}
to{
stroke-dashoffset: -16; /* length */
}
}
<svg viewBox='0 0 64 64'>
<g>
<line x1='32' y1='16' x2='32' y2='0' />
<line x1='41.40' y1='19.05' x2='50.80' y2='6.11' />
<line x1='47.21' y1='27.05' x2='62.43' y2='22.11' />
<line x1='47.21' y1='36.94' x2='62.43' y2='41.88' />
<line x1='41.40' y1='44.94' x2='50.80' y2='57.88' />
<line x1='32' y1='48' x2='32' y2='64' />
<line x1='22.59' y1='44.94' x2='13.19' y2='57.88' />
<line x1='16.78' y1='36.94' x2='1.56' y2='41.88' />
<line x1='16.78' y1='27.05' x2='1.56' y2='22.11' />
<line x1='22.59' y1='19.05' x2='13.19' y2='6.11' />
</g>
</svg>