I'm trying to create a simple loading animation using SVG and CSS but for some reason the spinning circle is slightly wobbling. It's hardly noticeable but it's driving me crazy.
Here's a link to Codepen demonstrating the problem: https://codepen.io/signorbusi/pen/dyeJqmE
This is the code:
#keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#spinner {
animation-name: spin;
margin-top: 2rem;
animation-duration: 0.5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
transform-origin: center center;
}
<div class="wrapper">
<svg id="spinner" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" stroke="black">
<circle r="23" cx="24" cy="24" stroke-width="2"/>
</svg>
</div>
Any pointers to how to get rid of the wobbling would be very helpful!
The viewbox of the <svg> element is cutting off the edges of the circle as it rotates. (Note that your stroke-width is increasing the size of the circle beyond the defined radius in the r attribute.)
If you expand the <svg> element's width and height attributes, match the viewbox attribute accordingly, and then also center the circle inside of that (using the cx and cy attributes on the <circle> element), it will not "wobble":
<div class="wrapper">
<svg id="spinner" xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" stroke="black">
<circle r="23" cx="30" cy="30" stroke-width="2"/>
</svg>
</div>
Working Codepen can be found here: https://codepen.io/theodorewiersema/pen/NWMXowY
This should work:
<circle r="22" cx="24" cy="24" stroke-width="2"/>
I changed the radius attribute to 22 and it doesn't wobble.
I'm having issues with the transform-origin while attempting to scale sub-elements.
While attempting to scale animate a box within a larger svg, it uses the transform origin (0,0) from the overall svg, rather than the center of the element I am trying to scale.
This makes it appear like it is "flying in from the top left" which is not what I am looking for. I am looking to make it scale from the elements center.
How do I get the transform-origin to be set relative to the specific element I am animating, without having to hardcode the (x,y) position of the sub-element itself.
Here is a simple example of the issue I'm dealing
#keyframes scaleBox {
from {transform: scale(0);}
to {transform: scale(1);}
}
#animated-box {
animation: scaleBox 2s infinite;
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" style="
width: 195px;
"><defs>
<style>.cls-1{fill:#7f7777;}.cls-2{fill:#fff;}</style>
</defs>
<rect class="cls-1" x="0.5" y="0.5" width="99" height="99"></rect>
<path d="M99,1V99H1V1H99m1-1H0V100H100V0Z"></path>
<rect id="animated-box" class="cls-2" x="10.5" y="8.5" width="22" height="6"></rect></svg>
You need transform-box: fill-box;
#keyframes scaleBox {
from {transform: scale(0);}
to {transform: scale(1);}
}
#animated-box {
transform-box: fill-box;
animation: scaleBox 2s infinite;
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" style="
width: 195px;
"><defs>
<style>.cls-1{fill:#7f7777;}.cls-2{fill:#fff;}</style>
</defs>
<rect class="cls-1" x="0.5" y="0.5" width="99" height="99"></rect>
<path d="M99,1V99H1V1H99m1-1H0V100H100V0Z"></path>
<rect id="animated-box" class="cls-2" x="10.5" y="8.5" width="22" height="6"></rect></svg>
I have a simple path, to which i'm applying a dash array and a dash offset with CSS. Then I'm animating this simple construct. The animation changes the dash array and offset to decrease and then increase size again.
The odd thing is, the movement appears to reverse halfway through. Can anyone help with this? I'm sure it's not actually reversing, but that the math is causing an unexpected visual effect.
.path {
stroke-dasharray: 10;
stroke-dashoffset: 10 30;
animation: dash 5s linear infinite;
}
#keyframes dash {
50%{
stroke-dashoffset: 35%;
stroke-dasharray: 0 87.5%;
}
}
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z"/>
</svg>
For props the above is a very boiled down version of this beautiful work.
per MDN
If a keyframe rule doesn't specify the start or end states of the animation (that is, 0%/from and 100%/to), browsers will use the element's existing styles for the start/end states. This can be used to animate an element from its initial state and back.
You've got one keyframe at 50% so animation goes to that at half-time and then back to the initial state at full time.
I'm trying to reverse how this SVG line animates. I need the line to draw from left to right but can only get it to work right to left. I tried changing the end point in illustrator but this only led to it drawing from both sides. How do I do this? You can see the animation here: http://mckeever02.github.io/voxbit/
This is the SVG:
<svg viewBox="0 0 759.7 234.2">
<path class="phone-line" stroke="#fff" stroke-width="4" stroke-dashoffset="20" fill="none" class="st0" d="M755.6,229.7H540.1c-31.9,0-57.6-27-57.6-58.9l0-5.8V61.6c0-31.9-26.1-58-58-58h-40.8h-7.9H335
M755.6,229.7H540.1c-31.9,0-57.6-27-57.6-58.9l0-5.8V61.6c0-31.9-26.1-58-58-58h-40.8h-7.9H335
c-31.9,0-58,26.1-58,58v103.3v6.8c0,31.9-26.1,58-58,58H11.55" />
</svg>
and the CSS to animate it:
.phone-line {
stroke-dasharray:1400;
-webkit-animation: draw 4s ease-in;
}
#-webkit-keyframes draw {
from {
stroke-dashoffset: 1400;
}
to {
stroke-dashoffset: 0;
}
}
As you would be aware, the stroke-dasharray property creates a dashed line pattern. When the value is assigned as 1400 it means that the length of the dash and the space between the dashes is 1400. That is for 0 to 1400 the line will be present and from 1400 to 2800 a dash would be present.
Now when you change the stroke-dashoffset from 1400 to 0 it brings the line into view from one direction. Initially the offset is at 1400 and thus only the dash is visible (no line). When the offset is animated to 0, the dash moves out towards the left and the line (that is present from 0 to 1400) slowly comes into view.
A simple method to do it from the other direction would be to animate it from 1400 to 2800. When this is done, the dash moves out towards the right as the line (that is present from 2800 to 4200) slowly comes into view.
.phone-line {
stroke-dasharray: 1400;
animation: draw 4s ease-in;
}
#keyframes draw {
from {
stroke-dashoffset: 1400;
}
to {
stroke-dashoffset: 2800;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<svg viewBox="0 0 759.7 234.2">
<path class="phone-line" stroke="#000" stroke-width="4" stroke-dashoffset="20" fill="none" class="st0" d="M755.6,229.7H540.1c-31.9,0-57.6-27-57.6-58.9l0-5.8V61.6c0-31.9-26.1-58-58-58h-40.8h-7.9H335
M755.6,229.7H540.1c-31.9,0-57.6-27-57.6-58.9l0-5.8V61.6c0-31.9-26.1-58-58-58h-40.8h-7.9H335
c-31.9,0-58,26.1-58,58v103.3v6.8c0,31.9-26.1,58-58,58H11.55" />
</svg>
Another approach (as mentioned by Paul LeBeau in comments) would be to animate it from -1400 to 0. This also produces the same output as the above snippet.
.phone-line {
stroke-dasharray: 1400;
animation: draw 4s ease-in;
}
#keyframes draw {
from {
stroke-dashoffset: -1400;
}
to {
stroke-dashoffset: 0;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<svg viewBox="0 0 759.7 234.2">
<path class="phone-line" stroke="#000" stroke-width="4" stroke-dashoffset="20" fill="none" class="st0" d="M755.6,229.7H540.1c-31.9,0-57.6-27-57.6-58.9l0-5.8V61.6c0-31.9-26.1-58-58-58h-40.8h-7.9H335
M755.6,229.7H540.1c-31.9,0-57.6-27-57.6-58.9l0-5.8V61.6c0-31.9-26.1-58-58-58h-40.8h-7.9H335
c-31.9,0-58,26.1-58,58v103.3v6.8c0,31.9-26.1,58-58,58H11.55" />
</svg>
Note: Ideal approach in my view would be to change the direction of your path itself to start from the left and move to the right instead of go from right to left. This is only a simple workaround to reverse the direction without altering the path.
I have a text logo in SVG and I want to animate the whole text not just the outline. Is there any way to do this? I can show you the code working and I'm including it below too.
<svg version="1.1" id="logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50%" height="50%;" viewBox="0 0 912 212" style="enable-background:new 0 0 912 212;" xml:space="preserve">
<defs>
<style type="text/css">
.st0{fill:none;stroke:#19a4dd;}
.st0{
stroke-dasharray: 2000;
stroke-dashoffset: 0;
-webkit-animation: dash 10s linear forwards;
-o-animation: dash 10s linear forwards;
-moz-animation: dash 10s linear forwards;
animation: dash 10s linear forwards;
}
#-webkit-keyframes dash {
from{
stroke-dashoffset: 2000;
}
to{
stroke-dashoffset: 0;
}
}
</style>
</defs>
<g>
<path class="st0" d="M195.683,105.006c0.077,12.928,9.039,25.168,26.274,25.245c8.196,0,14.708-2.907,21.065-9.716l-4.979-3.978
c-4.443,4.896-10.035,7.727-16.24,7.65c-10.188,0-17.695-6.656-19.074-15.759c0,0-0.23-1.989-0.306-3.672
c0-1.607,0.23-3.748,0.306-3.748c0.843-7.191,6.435-15.3,17.618-15.3c9.422,0,16.699,6.503,17.618,15.3l0.153,1.147h-13.559v4.973
h21.065c-0.46-16.677-10.648-27.387-25.202-27.464C205.411,79.837,195.683,91.236,195.683,105.006"/>
<path class="st0" d="M115.404,79.837c-15.244,0-26.121,11.628-26.121,25.245c0,13.77,10.265,25.092,26.121,25.092
s26.045-11.322,26.121-25.092C141.525,91.465,130.648,79.837,115.404,79.837 M115.481,132.316L115.481,132.316L115.481,132.316
M96.407,105.006c0-11.016,8.809-19.278,18.997-19.278s18.997,8.262,18.997,19.278c0,10.251-8.733,19.125-18.997,19.201
C105.139,124.207,96.483,115.257,96.407,105.006"/>
<path class="st0" d="M168.795,86.339c4.596,0,7.89,1.836,9.882,4.667c1.992,2.831,2.834,6.579,2.834,10.481v28.076h6.511V98.197
c0-6.503-2.451-10.863-6.052-13.693c-3.6-2.831-8.426-4.131-13.099-4.131s-9.652,1.301-13.405,4.131
c-3.753,2.831-6.358,7.191-6.358,13.693v31.365h6.511v-28.076c0-3.902,0.766-7.65,2.834-10.481
c1.992-2.831,5.362-4.667,9.882-4.667H168.795"/>
<path class="st0" d="M260.181,83.968c-3.753,2.831-6.358,7.191-6.358,13.693v31.365h6.511v-28.076c0-3.902,0.766-7.65,2.834-10.481
c1.992-2.831,5.362-4.667,9.882-4.667h0.153v-5.967C268.684,79.913,263.858,81.214,260.181,83.968"/>
<g>
<path class="st0" d="M40.028,129.103h19.61c7.967,0,13.635-3.213,17.465-7.803s5.669-10.71,5.669-16.371
s-1.915-11.781-5.669-16.371c-3.83-4.59-9.499-7.803-17.465-7.803h-19.61l6.358,6.12h10.571c4.979,0,9.728,1.301,13.329,4.208
c3.6,2.907,5.898,7.421,5.898,13.158l0,0v1.301l0,0c0,5.737-2.298,10.251-5.898,13.158c-3.6,2.907-8.35,4.284-13.329,4.284H40.028
V129.103z"/>
</g>
</g>
</svg>
I want the final effect to look like this.
Increase the stroke-width so it fills the shape and put a clip-path on the shape (use copy of the shape with the original stroke-width) so the stroke-width does not make the shape appear too bold.