SVG only (no JS) - line/path animation - css

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.

Related

SVG path element scale transition bug in Firefox browser

I am trying to animate a svg path element on hover by adding transform scale transition on it.
It works perfectly as intended on chrome, but on firefox it breaks the transition.
Note: It works without transition animation, but transition is needed in this use case.
HTML:
<svg viewBox="-1.1 -1.1 2.2 2.2">
<g>
<path d="M 1 0 A 1 1 0 0 1 -0.8085734960732691 0.5883951915573843 L 0 0" fill="#ACC6D9" stroke="#ACC6D9" stroke-width="0.01"></path>
<path d="M -0.8085734960732691 0.5883951915573843 A 1 1 0 0 1 -0.8100500340267164 -0.5863607612837983 L 0 0" fill="#93B5D1" stroke="#93B5D1" stroke-width="0"></path>
<path d="M -0.8100500340267164 -0.5863607612837983 A 1 1 0 0 1 0.3063859980740773 -0.9519073590345604 L 0 0" fill="#81A8C9" stroke="#81A8C9" stroke-width="0"></path>
<path d="M 0.3063859980740773 -0.9519073590345604 A 1 1 0 0 1 0.999992891049955 -0.0037706563822101314 L 0 0" fill="#6E9CC1" stroke="#6E9CC1" stroke-width="0"></path>
</g>
<circle cx="0" cy="0" r="0.5" fill="#393D45"></circle>
</svg>
CSS:
path{
transition: transform 0.2s;
}
path:hover{
transform: scale(1.1);
}
JSFiddle link: https://jsfiddle.net/tpkjf15b/2/
Edit:
Chrome 80 (desired output): GIF
Firefox 74 (broken): GIF
This is a weird bug, apparently caused by the fractional stroke-width as demonstrated by this reduced case:
path {
transform: scale(1, 1);
transition: transform 0.2s linear;
}
path:hover {
transform: scale(1.1, 1.1);
}
:checked ~ svg path {
stroke-width: 0.1;
stroke: red;
}
<input id="inp" type="checkbox"><label for="inp">add stroke</label><br>
<svg viewBox="-2.5 -2.5 10 10" width="300">
<path d="M0 0 L2.5 0 L0 2.5 Z" fill="#ACC6D9"></path>
<circle cx="0" cy="0" r="0.5" fill="#393D45"></circle>
</svg>
So for your case, since the strokes are set to the same color as the fills, you may be able to avoid this bug by redefining your shapes in a way you don't need that stroke hack. I guess you used it to avoid antialiasing artifacts, but instead of such an hack, you'd be better using integer coordinates when possible, or maybe simply using a viewBox that would allow stroke-width to be 1 could work.
Also, I didn't checked if this bug has already been referenced, but I can still reproduce on Nightly 76, so you might want to open an issue on Mozilla's bugzilla.
You need to write css transform: translate3d(0px,0px,1px) scale(1); property on path before hover and with hover need to write something like transform: translate3d(0px,0px,1px) scale(1.1);
Finally transform: translateZ(1px); make it run perfectly in FF.
Works too: transform: translate3d(0px,0px,1px);
I hope this will help you lot.
path{
transform: translate3d(0px,0px,1px) scale(1);
transition: transform 0.2s;
}
path:hover{
transform: translate3d(0px,0px,1px) scale(1.1);
}
<svg viewBox="-1.1 -1.1 2.2 2.2" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="backface-visibility: hidden;">
<g>
<path d="M 1 0 A 1 1 0 0 1 -0.8085734960732691 0.5883951915573843 L 0 0" fill="#ACC6D9" stroke="#ACC6D9" stroke-width="0.01"></path>
<path d="M -0.8085734960732691 0.5883951915573843 A 1 1 0 0 1 -0.8100500340267164 -0.5863607612837983 L 0 0" fill="#93B5D1" stroke="#93B5D1" stroke-width="0"></path>
<path d="M -0.8100500340267164 -0.5863607612837983 A 1 1 0 0 1 0.3063859980740773 -0.9519073590345604 L 0 0" fill="#81A8C9" stroke="#81A8C9" stroke-width="0"></path>
<path d="M 0.3063859980740773 -0.9519073590345604 A 1 1 0 0 1 0.999992891049955 -0.0037706563822101314 L 0 0" fill="#6E9CC1" stroke="#6E9CC1" stroke-width="0"></path>
</g>
<circle cx="0" cy="0" r="0.5" fill="#393D45"></circle>
</svg>

SVG line cross animation for icons

I have two icons, one in original state, one in crossed off state.
I want to animate the cross line but changing dash-offset is not useful since those are two different svgs.
I'm looking at these animated icons but still couldn't figure out the magic part. I want to ask:
what should be the transition work flow?
I prefer to use pure CSS, is it possible?
A working example would be appreciated.
The animated icons on that page are quite complicated (more that they need to be IMO). But basically what they are doing is sliding a rectangular mask in from right to left, that covers the first icon, and uncovers the second icon.
Here is a simplified version, using pure CSS, that hopefully makes it clearer.
svg {
width: 100px;
height: 100px;
}
/* slides the two masks to the left on hover */
svg:hover #bottom-rect,
svg:hover #top-rect
{
transition: transform 500ms;
transform: translate(-24px, 0px);
}
/* slides the two masks back to the right when not hovered */
svg #bottom-rect,
svg #top-rect {
transition: transform 500ms;
transform: translate(0px, 0px);
}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<defs>
<mask id="bottom">
<rect id="bottom-rect" width="24" height="24" fill="white" stroke="none"/>
</mask>
<mask id="top">
<rect id="top-rect" x="24" width="24" height="24" fill="white" stroke="none"/>
</mask>
</defs>
<g mask="url(#bottom)">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
<g mask="url(#top)">
<line x1="1" y1="1" x2="23" y2="23"></line>
<path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"></path>
<path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
</svg>
An approach with CSS.
You just show/hide the icons you want on hover. To animate the line, use CSS animations with stroke-dasharray and stroke-dashoffset. Comments in code.
/* for demo */
svg {
width: 100px;
height: 100px;
border: 1px solid black;
}
/* hide the off icon */
svg .off {
opacity: 0;
}
/* when user hovers SVG, the on icon is hidden... */
svg:hover .on {
opacity: 0;
}
/* ... and the off icon is shown */
svg:hover .off {
opacity: 1;
}
/* initial values for the stroke
-- these can be obtained with JS,
-- or you can work them out manually for CSS
*/
svg .line {
stroke-dashoffset: 40px;
stroke-dasharray: 40px;
}
/* when user hovers SVG, animate the line */
svg:hover .line {
animation: addLine 800ms forwards;
}
/* values for line animation */
#keyframes addLine {
from {
stroke-dashoffset: 40px;
}
to {
stroke-dashoffset: 0;
}
}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<g class="on">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
<g class="off">
<line class="line" x1="1" y1="1" x2="23" y2="23"></line>
<path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"></path>
<path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23"></path>
<line x1="12" y1="19" x2="12" y2="23"></line>
<line x1="8" y1="23" x2="16" y2="23"></line>
</g>
</svg>

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?

SVG g element height with css transition

I am stuck with an issue. my goal is to create a blinking eye in svg. I created the graphic converted into svg. Now i planned to put a css animation on it so it looks like its blinking. I spent lot of time on it but not able to solve the issue.
my approach to achieve this effect is to change its g element height with css transition so it will looks like blinking but when i put css on it it just disappear :( below is the css code I used:
#svg_7 path{
transform:scale(0, -1);
-webkit-transform:scale(0, -1);
}
svg code
<g id="svg_7">
<path id="svg_8" d="m35.99502,49.21692c-11.88306,0 -22.25696,5.59302 -27.80701,13.90399c5.55103,8.31104 15.92505,13.90302 27.80701,13.90302c11.88306,0 22.25696,-5.59198 27.80896,-13.90302c-5.55299,-8.31097 -15.92701,-13.90399 -27.80896,-13.90399z" stroke-miterlimit="10" stroke-width="1.4434" stroke="#fa5400" fill="transparent" />
<circle id="svg_9" r="9.83801" cy="63.12191" cx="35.995" stroke-miterlimit="10" stroke-width="1.4434" stroke="#fa5400" fill="transparent" />
Main purpose is to create a blinking eye that keeps blinking after every few seconds. please do suggest me a solution. even we can use js/jquery if required.
jsfiddle link
thanks in advance
Kax
In fact to have the closest effect (to reality) of blinking eye, I think you have to redesign the eye. Such as we need to animate the upper eyelid only (not both). Also the inner pupil should be covered by the eye lid. Doing so is not easy, at least I feel like that it can be done more easily with CSS than with SVG. However the time of shutting the eye lid is short, we can just animate both the eyelid and the inner pupil. Scaling down the vertical size of both to nearly 0 should do the job. However we can notice that the stroke-width becomes thinner at such a small scaling (may create some visible dashed lines instead of a solid one). So we also have to animate (increase) the stroke-width. Here is the CSS code (please run it in webkit-based browsers, it should work for all browsers):
#svg_7 path{
-webkit-transform-origin:50%;
-webkit-animation:blink 3s infinite alternate;
}
#svg_9 {
-webkit-transform-origin:50%;
-webkit-animation:coreblink 3s infinite alternate;
}
#-webkit-keyframes blink {
0%, 96% {
-webkit-transform:scale(1,1);
stroke-width:1.4434px;
}
100% {
-webkit-transform:scale(1,0.05);
stroke-width:6px;
}
}
#-webkit-keyframes coreblink {
0%, 96% {
-webkit-transform:scale(1,1);
}
100% {
-webkit-transform:scale(1,0.05);
}
}
Note that, if you increase the animation-duration (it's 3s in the demo), you should also increase the key percentage (it's 96% in the demo) so that the time of shutting the eye lid is not considerably large. I know this is not perfect (as what I said before), but it's at least acceptable in some use case and hope you are satisfied with it.
Demo.
UPDATE: If you want to save the SVG code into a file, you should also ship the CSS code (used to animate the SVG) along with the SVG file by using <style> tag like this:
<svg width="99" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<style>
#svg_7 path{
-webkit-transform-origin:50%;
-webkit-animation:blink 3s infinite alternate;
}
#svg_9 {
-webkit-transform-origin:50%;
-webkit-animation:coreblink 3s infinite alternate;
}
#-webkit-keyframes blink {
0%, 96% {
-webkit-transform:scale(1,1);
stroke-width:1.4434px;
}
100% {
-webkit-transform:scale(1,0.05);
stroke-width:6px;
}
}
#-webkit-keyframes coreblink {
0%, 96% {
-webkit-transform:scale(1,1);
}
100% {
-webkit-transform:scale(1,0.05);
}
}
</style>
<g id="svg_1">
<rect id="svg_2" height="71.991" width="71.99" stroke-miterlimit="10" stroke-width="1.4434" stroke="#ffffff" fill="transparent" y="0.71191" x="26.195"/>
<line id="svg_3" y2="0.71191" x2="26.195" y1="27.12591" x1="0" stroke-miterlimit="10" stroke-width="1.4434" stroke="#ffffff" fill="transparent"/>
<line id="svg_4" y2="72.70391" x2="26.195" y1="99.11691" x1="0" stroke-miterlimit="10" stroke-width="1.4434" stroke="#ffffff" fill="transparent"/>
<rect id="svg_5" height="71.991" width="71.992" stroke-miterlimit="10" stroke-width="1.4434" stroke="#ffffff" fill="#000000" y="27.12491" x="0"/>
<g id="svg_6">
<g id="svg_7">
<path id="svg_8" d="m35.99502,49.21692c-11.88306,0 -22.25696,5.59302 -27.80701,13.90399c5.55103,8.31104 15.92505,13.90302 27.80701,13.90302c11.88306,0 22.25696,-5.59198 27.80896,-13.90302c-5.55299,-8.31097 -15.92701,-13.90399 -27.80896,-13.90399z" stroke-miterlimit="10" stroke-width="1.4434" stroke="#fa5400" fill="transparent">
</path>
<circle id="svg_9" r="9.83801" cy="63.12191" cx="35.995" stroke-miterlimit="10" stroke-width="1.4434" stroke="#fa5400" fill="transparent" />
</g>
</g>
<polygon id="svg_10" points="98.1849594116211,72.70391845703125 71.9919662475586,99.116943359375 71.9919662475586,27.12591552734375 98.1849594116211,0.7119140923023224 " stroke-miterlimit="10" stroke-width="1.4434" stroke="#ffffff" fill="transparent"/>
</g>
</svg>
Another approach is try using pure SVG animate. However I find it hard to have an equivalent of SVG animation to CSS animation.

Resources