I'm trying to animate circles to achieve an infinite effect of colliding waves.
I laid the base but I can't make the order of the animations smooth and linear.
Codepen available here.
<div class="circles-container"
<!-- 1er circle -->
<svg width="1280" height="1280" xmlns="http://www.w3.org/2000/svg" style="z-index: 1;">
<path class="circle-1" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
<!-- 2eme circle -->
<svg width="1280" height="1280" xmlns="http://www.w3.org/2000/svg" style="z-index: 2;">
<path class="circle-2" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
<!-- 3eme circle -->
<svg width="1280" height="1280" xmlns="http://www.w3.org/2000/svg" style="z-index: 3;">
<path class="circle-3" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
</div>
.circles-container { position: relative; }
.circles-container svg {
position: absolute;
top: 0;
left: 0;
}
.circle-1 {
animation: scaleCircle 7.5s ease-in-out infinite;
transform: scale(0);
transition: all 2s ease-in-out;
color: #1D1D28;
}
.circle-2 {
animation: scaleCircle 5s ease-in-out infinite 2.5s;
transform: scale(0);
transition: all 2s ease-in-out;
color: #420DC4;
}
.circle-3 {
animation: scaleCircle 5s ease-in-out infinite;
transform: scale(0);
transition: all 2s ease-in-out;
color: #1D1D28;
}
#keyframes scaleCircle {
0% {
transform: scale(0);
}
100% {
transform: scale(2);
}
}
Here is the scenario:
When loading, a first blue circle is displayed.
A first black circle grows until it crushes the blue circle
at 50% of step's 1 animation, a new blue circle is displayed and enlarged until it overwrites the black circle created during step 1
back to step 1
In my render, you can see that the circles are showing but some are hiding too soon, etc. The circles should display one after the other in a linear fashion.
Is it possible to do this in full CSS with keyframes ?
Not sure if this is exactly what you are going for but maybe you can tinker with it.
So with 4 circles you can animate the scale basically the way you have it. And then for their svg container, you animate the z-index so whenever a wave starts it gets its highest z-index and then it deceases before the next wave starts.
<div class="circles-container">
<!-- 1er cercle -->
<svg class="circle-parent-1" width="1280" height="1280" xmlns="http://www.w3.org/2000/svg">
<path class="circle-1" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
<!-- 2eme cercle -->
<svg class="circle-parent-2" width="1280" height="1280" xmlns="http://www.w3.org/2000/svg" >
<path class="circle-2" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
<svg class="circle-parent-3" width="1280" height="1280" xmlns="http://www.w3.org/2000/svg" >
<path class="circle-3" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
<svg class="circle-parent-4" width="1280" height="1280" xmlns="http://www.w3.org/2000/svg" >
<path class="circle-4" d="M0 0h640c0 353.466-286.534 640-640 640V0Z" fill="currentColor" fill-rule="evenodd" />
</svg>
body {
margin: 0;
padding: 0;
}
.circles-container { position: relative; }
.circles-container svg {
position: absolute;
top: 0;
left: 0;
}
.circle-parent-1 {
animation: zIndexCircle 8s ease-in-out infinite;
animation-delay: 0s;
}
.circle-parent-2 {
animation: zIndexCircle 8s ease-in-out infinite;
animation-delay: 2s;
}
.circle-parent-3 {
animation: zIndexCircle 8s ease-in-out infinite;
animation-delay: 4s;
}
.circle-parent-3 {
animation: zIndexCircle 8s ease-in-out infinite;
animation-delay: 4s;
}
.circle-parent-4 {
animation: zIndexCircle 8s ease-in-out infinite;
animation-delay: 6s;
}
.circle-1 {
animation: scaleCircle 8s ease-in-out infinite;
animation-delay:0s;
transform: scale(0);
color: #1D1D28;
}
.circle-2 {
animation: scaleCircle 8s ease-in-out infinite;
animation-delay:2s;
transform: scale(0);
color: #420DC4;
}
.circle-3 {
animation: scaleCircle 8s ease-in-out infinite;
animation-delay:4s;
transform: scale(0);
color: #1D1D28;
}
.circle-4 {
animation: scaleCircle 8s ease-in-out infinite;
animation-delay:6s;
transform: scale(0);
color: #420DC4;
}
#keyframes zIndexCircle {
0% {
z-index:5;
}
25% {
z-index: 4;
}
50% {
z-index:3;
}
75% {
z-index:2;
}
100% {
z-index:1;
}
}
#keyframes scaleCircle {
0% {
transform: scale(0);
}
75% {
transform: scale(2);
}
100% {
transform: scale(2);
}
}
https://codepen.io/todilo-the-vuer/pen/XWEmdXL
the required loader is to be of the following gif given above but needs to be implemented in a svg.
the code given below is the svg I have implemented so far but I am not able to get the required animation as that of a gif. Can somebody point out where I am going wrong or help me with how to get the animations right. Thanks in advance
svg{
width: 250px;
height: 250px;
position: relative;
}
/* .circles{
transform: rotate(-90deg);
} */
#inner{
stroke-dasharray: 314 314;
stroke-dashoffset: 314;
transform: rotate(-90deg);
transform-origin: 50% 50%;
/* animation: rotate 2s linear infinite; */
animation: animate 2s ease-in-out infinite;
}
#keyframes animate{
0%,100%{
stroke-dashoffset: 314;
}
50%{
stroke-dashoffset: 0;
}
50.1%{
stroke-dashoffset: 628 ;
}
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="svg.css">
<title>Document</title>
</head>
<body>
<svg>
<g class="circles">
<circle cx="125" cy="125" r="50" fill="none" stroke-width="15px" stroke="#E0E3E9">
</circle>
<circle id="inner" cx="125" cy="125" r="50" fill="none" stroke-width="12px" stroke="#6B04A8">
</circle>
</g>
</svg>
</body>
</html>
I hope this is what you need: instead of animating the stroke-dashoffset I'm animating the stroke-dasharray
svg {
width: 250px;
height: 250px;
position: relative;
}
/* .circles{
transform: rotate(-90deg);
} */
#inner {
stroke-dasharray: 1 314;
stroke-dashoffset: 314;
transform: rotate(-90deg);
transform-origin: 50% 50%;
/* animation: rotate 2s linear infinite; */
animation: animate 2s ease-in-out infinite;
}
#keyframes animate {
100% {
stroke-dasharray: 314;
}
}
svg {
border: 1px solid;
}
<svg>
<g class="circles">
<circle cx="125" cy="125" r="50" fill="none" stroke-width="15px" stroke="#E0E3E9">
</circle>
<circle id="inner" cx="125" cy="125" r="50" fill="none" stroke-width="12px" stroke="#6B04A8">
</circle>
</g>
</svg>
Second attempt:
The OP is commenting
for the first 50% of the circle it has to grow and after crossing the 50% only it should shrink
svg {
width: 250px;
height: 250px;
position: relative;
}
/* .circles{
transform: rotate(-90deg);
} */
#inner {
transform: rotate(-90deg);
transform-origin: 50% 50%;
animation: animate 5s ease-in-out infinite;
}
#keyframes animate{
0%{
stroke-dasharray: 0 314;
stroke-dashoffset: 314;
}
50%{
stroke-dasharray: 157 157;
stroke-dashoffset: 314;
}
75%{
stroke-dasharray: 157 157;
stroke-dashoffset: 157;
}
100%{
stroke-dasharray: 0 314;
stroke-dashoffset: 0;
}
}
svg {
border: 1px solid;
}
<svg>
<g class="circles">
<circle cx="125" cy="125" r="50" fill="none" stroke-width="15px" stroke="#E0E3E9">
</circle>
<circle id="inner" cx="125" cy="125" r="50" fill="none" stroke-width="12px" stroke="#6B04A8" stroke-dasharray="0 314" stroke-dashoffset = "157">
</circle>
</g>
</svg>
I want to move SVG elements across their container using CSS keyframes.
If I had just a <circle />, I could simply use the cx / cy properties in the keyframe definition. But what if I had an arbitrary group (<g />)? A group doesn't have cx / cy, and it seems that I have to define a unit (like px) if I wanted to use CSS' transform: translate(x,y).
MWE (how do I animate the bar group?):
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
.foo {
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveFoo;
}
.bar {
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveBar;
}
#keyframes moveFoo {
from {
cx: 10;
cy: 10;
}
to {
cx: 90;
cy: 90;
}
}
/* how to define this? */
#keyframes moveBar { }
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" fill="red" />
<g class="bar" transform="translate(90 10)">
<circle r="5" fill="blue" />
<text
y="1"
text-anchor="middle"
fill="white"
font-family="monospace"
font-size="5">
AB
</text>
</g>
</svg>
Use animateTransform to do this:
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" fill="red" />
<g id="bar" transform="translate(90 10)">
<circle r="5" fill="blue" />
<text
y="1"
text-anchor="middle"
fill="white"
font-family="monospace"
font-size="5">
AB
</text>
</g>
<animateTransform xlink:href="#bar"
attributeName="transform"
type="translate"
from="90,10" to="90,90"
dur="2" repeatCount="indefinite"/>
</svg>
it seems that I have to define a unit (like px) if I wanted to use
CSS' transform: translate(x,y).
Yes, it's true, you do.
But that won't be an issue, if you have already declared a viewbox attribute in the <svg> element.
If you have declared a viewbox, 1px will represent 1 viewbox unit.
Working Example:
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
.foo {
fill: red;
transform: translate(10px, 10px);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveFoo;
}
.bar {
transform: translate(90px, 10px);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveBar;
}
.bar circle {
fill: blue;
}
.bar text {
fill: white;
font-family: monospace;
font-size: 5px;
text-anchor: middle;
}
#keyframes moveFoo {
0% {transform: translate(10px, 10px);}
50% {transform: translate(90px, 90px);}
100% {transform: translate(10px, 10px);}
}
#keyframes moveBar {
0% {transform: translate(90px, 10px);}
50% {transform: translate(10px, 90px);}
100% {transform: translate(90px, 10px);}
}
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" />
<g class="bar">
<circle r="5" />
<text y="1">AB</text>
</g>
</svg>
If you need to use #keyframes instead of animating the cx and cy attributes you have to animate from transform:translate(0,0) to transform:translate(90px,90px) (for example.)
Otherwise Temani Afif's answer is perfectly valid.
`
svg {
padding: 5px;
width: 150px;
height: 150px;
border: 1px solid #000;
}
.foo {
transform:translate(0,0);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveFoo;
}
.bar {
transform:translate(0,0);
animation-duration: 3s;
animation-iteration-count: infinite;
animation-name: moveBar;
}
#keyframes moveFoo {
from {
transform:translate(0,0)
}
to {
transform:translate(90px,90px)
}
}
/* how to define this? */
#keyframes moveBar {
from {
transform:translate(0,0)
}
to {
transform:translate(90px,90px)
}
}
<svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle class="foo" r="5" fill="red" />
<g class="bar" >
<circle r="5" fill="blue" cx="10" cy="10" />
<text
x="10"
y="11"
text-anchor="middle"
fill="white"
font-family="monospace"
font-size="5">
AB
</text>
</g>
</svg>
I am trying to add the CSS code inside the HTML but I am having trouble getting the SVG animation to work. What am I doing wrong here? My guest is that I am referencing <style> wrongly but after a couple of tries I can't make it work.
<svg>
<style type="text/css">
.spinner {
animation: rotate 2s linear infinite;
z-index: 2;
position: absolute;
top: 50%;
left: 50%;
margin: -25px 0 0 -25px;
width: 50px;
height: 50px;
}
.path {
stroke: hsl(210, 70, 75);
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
#keyframes rotate {
100% {
transform: rotate(360deg);
}
}
#keyframes dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}
</style>
<svg class="spinner">
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"</circle>
</svg>
</svg>
CodePen
Thank you in advance.
Your animation works. You messed up stroke color definition. hsl(210, 70%, 75%);
and circle elements opening tag is missing closing bracket >
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5" > </circle>
html, body {
height: 100%;
background-color: #000000;
}
<svg>
<style type="text/css">
.spinner {
animation: rotate 2s linear infinite;
transform-origin:center center;
z-index: 2;
position: absolute;
top: 50%;
left: 50%;
margin: -25px 0 0 -25px;
width: 50px;
height: 50px;
}
.path {
stroke: hsl(210, 70%, 75%);
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
#keyframes dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}
</style>
<g class="spinner">
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
</g>
</svg>
you need to close the html tag for circle
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"</circle>
should be
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
So I made a bunch of edits to an SVG file and now I can't open in in AI and it will not display on web. I'm guessing it is due to the fact that I have HTML elements inside it like the tags but I am not sure how to get around that without breaking the rest of the code.
<div>
<div id="banner">
<div>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
<defs>
<clipPath id="drop">
<path transform="scale(0.75), translate(32,0)" d="M68.2,6.7c0,0-62.4,70.9-62.4,124.7c0,32.3,28,58.4,62.4,58.4s62.4-26.2,62.4-58.4
C130.7,77.6,68.3,6.7,68.2,6.7z M61,77.5c0.8,0,1.5,0.7,1.5,1.5v20.6c2.7-3.6,7.6-5.7,13.1-5.7c12.2,0,19.4,6.9,19.4,18.7v37.2
c0,0.8-0.7,1.5-1.5,1.5H75.6c-0.8,0-1.5-0.7-1.4-1.5v-32c0-4.1-1.8-6.4-5-6.4c-5.8,0-6.7,5.7-6.7,5.7v32.7c0,0.8-0.7,1.5-1.5,1.5
H43.1c-0.8,0-1.5-0.7-1.5-1.5V79c0-0.8,0.7-1.5,1.5-1.5H61z" />
</clipPath>
</defs>
<g clip-path="url(#drop)">
<g class="fill">
<path fill="#04ACFF" id="waveShape" d="M300,300V2.5c0,0-0.6-0.1-1.1-0.1c0,0-25.5-2.3-40.5-2.4c-15,0-40.6,2.4-40.6,2.4
c-12.3,1.1-30.3,1.8-31.9,1.9c-2-0.1-19.7-0.8-32-1.9c0,0-25.8-2.3-40.8-2.4c-15,0-40.8,2.4-40.8,2.4c-12.3,1.1-30.4,1.8-32,1.9
c-2-0.1-20-0.8-32.2-1.9c0,0-3.1-0.3-8.1-0.7V300H300z" />
</g>
</g>
<g transform="scale(0.75), translate(32,0)">
<path class="st0" d="M68.2,6.7c0,0-62.4,70.9-62.4,124.7c0,32.3,28,58.4,62.4,58.4s62.4-26.2,62.4-58.4
C130.7,77.6,68.3,6.7,68.2,6.7z" />
<path class="st1" d="M61,77.5c0.8,0,1.5,0.7,1.5,1.5v20.6c2.7-3.6,7.6-5.7,13.1-5.7c12.2,0,19.4,6.9,19.4,18.7v37.2
c0,0.8-0.7,1.5-1.5,1.5H75.6c-0.8,0-1.5-0.7-1.4-1.5v-32c0-4.1-1.8-6.4-5-6.4c-5.8,0-6.7,5.7-6.7,5.7v32.7c0,0.8-0.7,1.5-1.5,1.5
H43.1c-0.8,0-1.5-0.7-1.5-1.5V79c0-0.8,0.7-1.5,1.5-1.5H61z" />
</g>
<defs>
<style type="text/css">
.st0 {
fill: none;
stroke: #000;
stroke-width: 4;
stroke-miterlimit: 5;
}
.st1 {
fill: none;
stroke: #fff;
stroke-width: 3;
stroke-miterlimit: 5;
}
#banner {
border-radius: 50%;
width: 150px;
height: 150px;
background: #fff;
overflow: hidden;
backface-visibility: hidden;
transform: translate3d(0, 0, 0);
}
#banner .fill {
animation-name: fillAction;
animation-iteration-count: 1;
animation-timing-function: cubic-bezier(.2, .6, .8, .4);
animation-duration: 4s;
animation-fill-mode: forwards;
}
#banner #waveShape {
animation-name: waveAction;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: 0.5s;
width: 300px;
height: 150px;
fill: #04ACFF;
}
#keyframes fillAction {
0% {
transform: translate(0, 150px);
}
100% {
transform: translate(0, -5px);
}
}
#keyframes waveAction {
0% {
transform: translate(-150px, 0);
}
100% {
transform: translate(0, 0);
}
}
</style>
</defs>
</svg>
</div>
</div>
</div>