SVG stroke dash array CSS animation reverses course? - css

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.

Related

SVG only (no JS) - line/path animation

I can't think my way through this one... I can't really add mark-up in a project, only CSS (for many boring reasons with who I'm collaborating remotely with).
The end client wants a loading animation of their logo path being drawn but not linear, more ease-in-out (slow-fast-slow) sort of thing. To illustrate what I mean, see jsfiddle I've done: https://jsfiddle.net/tobzzzz/djf7oth2/ (their logo is a bit like a speech mark, I've done a circle for ease for the demo).
The logo will sit on top of an image background, not a white/solid colour background, so my fiddle solution won't work of two circles layered. I added light grey background to demonstrate how it doesn't work.
The IDEAL solution would be SVG only (using SVG animation not CSS animation), I'd then convert it into data and put it as a background-image.
If it can't be done with SVG animation only, I'd like to know if it can be done with SVG and CSS combo. But it absolutely 100% cannot be JS.
Any good ideas?
body {
background: #eee
}
.black {
stroke-dasharray: 350;
stroke-dashoffset: 350;
animation: dash 4s linear infinite;
}
.white {
stroke-dasharray: 350;
stroke-dashoffset: 350;
animation: dash2 4s ease-in-out infinite;
}
#keyframes dash {
80% {
stroke-dashoffset: 0;
}
}
#keyframes dash2 {
100% {
stroke-dashoffset: 0;
}
}
<svg class="path" width="84" height="84" xmlns="http://www.w3.org/2000/svg">
<path class="black" fill="none" stroke="#000000" stroke-width="4" d="M 80.889194,41.80541 C 80.889194,63.45198 63.341174,81 41.694594,81 20.048024,81 2.5,63.45198 2.5,41.80541 2.5,20.158827 20.048024,2.61081 41.694594,2.61081 c 21.64658,0 39.1946,17.548017 39.1946,39.1946 z"/>
<path class="white" fill="none" stroke="white" stroke-width="5" d="M 80.889194,41.80541 C 80.889194,63.45198 63.341174,81 41.694594,81 20.048024,81 2.5,63.45198 2.5,41.80541 2.5,20.158827 20.048024,2.61081 41.694594,2.61081 c 21.64658,0 39.1946,17.548017 39.1946,39.1946 z"/>
</svg>
You need to animate the stroke-dasharray, not only the stroke-dashoffset. You can add multiple numbers to the value of the dasharray, defining alternating lengths of dashes and gaps. So, if you circle with r="40" has a circumference of 251,4,
0 251.4 is a stroke of 0 length and a gap around the whole circumference
125.7 125.7 is a half-circle stroke and a half-circle gap
and then reduce the stroke length again
At the same time, move the start of the stroke around the circle by animating the offset.
There is a lot of finetuning you can do with other intermediate values, by distributing the keyTimes differently and with easing functions. Here is a basic variant with linear animations:
<svg width="84" height="84">
<circle r="40" cx="42" cy="42" style="fill: none;stroke: black;stroke-width: 4;">
<animate attributeName="stroke-dasharray" dur="3s" repeatCount="indefinite"
keyTimes="0;0.5;1" values="0 251.4;125.7 125.7;0 251.4" />
<animate attributeName="stroke-dashoffset" dur="3s" repeatCount="indefinite"
keyTimes="0;0.5;1" values="0;-100;-251.4" />
</circle>
</svg>
Inkscape makes it easy to modify a path and to save it.
Below the svg includes from and to paths.
The tag animate after a 1 second delay makes the eye blinks twice and then stops:
<svg style="vertical-align:middle;opacity:0.7"
width="13" height="13"
viewBox="0 0 12 12"
xmlns="http://www.w3.org/2000/svg">
<path id="glass_1" d="m6 3c2.58 0 4.23 2.07 4.84 3-.62.93-2.26 3-4.84 3s-4.23-2.07-4.84-3c.62-.93 2.26-3 4.84-3m0-1c-4 0-6 4-6 4s2 4 6 4 6-4 6-4-2-4-6-4zm0 2a2 2 0 1 0 2 2 2 2 0 0 0 -2-2z"
fill="green">
</path>
<animate xlink:href="#glass_1" attributeName="d" attributeType="XML"
from="m6 3c2.58 0 4.23 2.07 4.84 3-.62.93-2.26 3-4.84 3s-4.23-2.07-4.84-3c.62-.93 2.26-3 4.84-3m0-1c-4 0-6 4-6 4s2 4 6 4 6-4 6-4-2-4-6-4zm0 2a2 2 0 1 0 2 2 2 2 0 0 0 -2-2z"
to="m6.1 5.9c2.6 0 3-0.019 4.7 0.092-1.4 0.58-2.2 0.59-4.7 0.59s-3.8 0.0053-4.9-0.59c1.2-0.069 2.4-0.092 5-0.092m0-1c-4 0-6.1 1.1-6.1 1.1s2.1 1.6 6.1 1.6c4 0 5.9-1.6 5.9-1.6s-1.9-1.1-5.9-1.1zm-0.13-0.91c-1.8 0-2.7 2.2-1.4 3.4s3.4 0.37 3.4-1.4c0-1.1-0.9-2-2-2z"
begin="1s;op.end"
repeatCount="2"
dur="0.5s">
</animate>
</svg>
have you looked at this?
https://maxwellito.github.io/vivus-instant/
You can drag in any SVG and it has limited animation capabilities automatically.

How to clip border partially with CSS (or SVG)?

I want to clip border of div which have some border-radius to imitate how timer expires.
But can't find any way to do it except like with clip-path: polygon(...)
But building custom polygon seems like really hard way to control border length.
Is there some simpler/ more elegant way to do it with CSS (or maybe SVG)?
Here is image of desirable result with few states ⇩⇩
pure svg
The effect of drawing a line is achieved using the attribute of the line stroke-dashoffset, which is an indent from the beginning of the line.
The line is hidden when stroke-dashoffset has a maximum value and is fully visible whenstroke-dashoffset = "0"
Therefore, changing the value of stroke-dashoffset from max to zero, we get the effect of drawing the line.
<svg version="1.1" id="map_line_svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300" viewBox="0 0 300 300" >
<rect x="50" y="100" width="200" height="100" rx="50" fill="#E0E9F6" stroke-width="4" stroke="grey" stroke-dashoffset="600" stroke-dasharray="600">
<animate attributeName="stroke-dashoffset" begin="1s" from="600" to="0" dur="7s" repeatCount="indefinite" />
</rect>
</svg>
CSS+SVG
This example is exactly the same as the first example, but the styles of the display style are transferred to an external stylesheet. More information on the drawing technique can be found here - Chris Coyier - stroke-dashoffset
You correctly noticed that the length of the line can be calculated using the JS method - getTotalLength ()
Here is an example of a script that prints the length of the path for figures drawn with path:
<script>
function TotalLength(){
var path = document.querySelector('#check');
var len = Math.round(path.getTotalLength() );
alert("Path length - " + len);
};
</script>
Below is a complete example of animation:
#rect1 {
stroke-dasharray: 600;
stroke-dashoffset: 600;
animation: dash 5s linear alternate infinite;
}
#keyframes dash {
from {
stroke-dashoffset: 600;
}
to {
stroke-dashoffset: 0;
}
}
#rect1 {
fill:#E0E9F6;
stroke-width:4;
stroke:grey;
}
<svg version="1.1" id="map_line_svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300" viewBox="0 0 300 300" >
<rect id="rect1" x="50" y="100" width="200" height="100" rx="50" />
</svg>
If you need an animation of the movement of the line in one direction, replace the alternate with forwards
I think that you do not need to animate the offset in this case. In the case of passing through the zero point as well as if you want to start not from the zero point problems may arise.
I would use 2 parameters - the stroke length and the stroke space, like:
<animate attributeName="stroke-dasharray" from="0 600" to="600 0" />

Animating SVG with CSS

I have a simple line SVG that is animating correctly. The problem is that on first load the SVG paths show and then disappear prior to the start.I have tried setting opacity on st1 and st2 to 0 and then keyframes to to opacity 1. This kind of works, but the SVG then disappears after it is run.
Am I missing something simple?
<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"
viewBox="0 0 485 500.9" style="enable-background:new 0 0 485 500.9;" xml:space="preserve">
<style type="text/css">
.st0{clip-path:url(#SVGID_2_);fill:none;stroke:#FFFFFF;stroke-dasharray: 1000;
animation: draw 4s normal ease-in;}
.st1{clip-path:url(#SVGID_2_);fill:none;stroke:#FFFFFF;stroke-dasharray: 1000;
animation: draw 4s normal ease-in;animation-delay: 1s;}
.st2{clip-path:url(#SVGID_2_);fill:none;stroke:#FFFFFF;stroke-dasharray: 1000;
animation: draw 4s normal ease-in;animation-delay: 3s;}
#keyframes draw {
from {
stroke-dashoffset: -1000;
}
to {
stroke-dashoffset: 0;
}
}
</style>
<g>
<defs>
<rect id="SVGID_1_" x="-0.1" y="0" width="485" height="501"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<path class="st0" d="M0.4,97.4c0-14.2,14.2-14.2,14.2-14.2H100l5.1,0h86.3c0,0,14.2,0,14.2-14.2V36.4V0"/>
<path class="st1" d="M207.5,236.3l0-31.3c0,0,0-14.2-14.2-14.2h-15.1l-142.8,0.1H14.6c-14.2,0-14.2-14.2-14.2-14.2V103"/>
<path class="st2" d="M484.9,500.5H221.8c-14.2,0-14.2-14.2-14.2-14.2l-0.1-242.6"/>
</g>
</svg>
See:
https://jsfiddle.net/suLkr4po/
How do I restructure this so each path comes in after the other has finished from top to bottom?
Add animation-fill-mode: backwards to the style of the animated elements. That will apply the start value before the animation is started.

Determine startpoint svg animation

I have exported an svg file from Illustrator.
Now I'm animating the line work. I know how to change the direction of animating but how (if) is it possible to determine the startpoint of the animation?
Here is an example:
#keyframes lines { 0% {fill: none;} 50% {fill: none; stroke-dashoffset: 0;} 100% {fill: none ;stroke-dashoffset: 0;} }
.nose_outer{ animation: lines 4s ease forwards; stroke-dasharray: 186.514; stroke-dashoffset: -186.514; }
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 768 768">
<title>svg</title>
<g><!-- NOSE OUTER -->
<path class="nose_outer" d="M396.667,406.31A17.016,17.016,0,0,0,381,416.686a17.008,17.008,0,1,0,0,13.266,17.011,17.011,0,1,0,15.667-23.642Z" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="5"/>
</g>
</svg>
By using negative and positive values on the stroke-dashoffset it's possible to change the direction.
Do I have to change something in Illustrator before exporting to svg?

Reverse SVG line drawing animation

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.

Resources