Reverse css keyframe animation - css

I've written a css animation using keyframes for svg path
path {
animation: anim 1s linear;
animation-fill-mode: forwards;
}
#keyframes anim {
50% {
d: path('M20 20 L 20 20');
}
100% {
d: path('M10 10 L 30 30');
}
}
<path class="top" d="M10 10 L 30 10" stroke-width="2" stroke="black" fill="transparent" />
Source
If you click on the svg you can see the animation in action. Now, if you click again I want it to animation to its original state. I've tried adding
transition: all 1s ease-out;
and
animation-direction: alternate;
But still there is no animation back to its initial state.
So the question is, how can I animate back?

With transition you can easily do this but the animation will be slightly different:
const svg = document.querySelector('svg');
svg.addEventListener('click', () => {
svg.classList.toggle('close');
});
svg {
border: 1px solid blue;
}
svg path {
transition: 0.2s all linear;
}
svg.close path.top {
d: path('M10 10 L 30 30');
}
svg.close path.middle {
d: path('M20 20 L 20 20');
}
svg.close path.bottom {
d: path('M10 30 L 30 10');
}
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
<path class="top" d="M10 10 L 30 10" stroke-width="2" stroke="black" fill="transparent"/>
<path class="middle" d="M10 20 L 30 20" stroke-width="2" stroke="black" fill="transparent"/>
<path class="bottom" d="M10 30 L 30 30" stroke-width="2" stroke="black" fill="transparent"/>
</svg>
Another idea is to rely on animationiteration where the trick is to run an infinite animation and you stop it on each iteration.
const svg = document.querySelector('svg');
const path = document.querySelector('svg path');
svg.addEventListener('click', () => {
svg.classList.toggle('close');
});
path.addEventListener('animationiteration', () =>{
svg.classList.toggle('close');
});
svg {
border: 1px solid blue;
}
path.top {
animation: close-top 0.2s linear infinite alternate;
}
path.middle {
animation: close-middle 0.2s linear infinite alternate;
}
path.bottom {
animation: close-bottom 0.2s linear infinite alternate;
}
svg:not(.close) path {
animation-play-state: paused;
}
svg.close path {
animation-play-state: running;
}
#keyframes close-top {
50% {
d: path('M20 20 L 20 20');
}
100% {
d: path('M10 10 L 30 30');
}
}
#keyframes close-middle {
to {
d: path('M20 20 L 20 20');
}
}
#keyframes close-bottom {
50% {
d: path('M20 20 L 20 20');
}
100% {
d: path('M10 30 L 30 10');
}
}
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
<path class="top" d="M10 10 L 30 10" stroke-width="2" stroke="black" fill="transparent"/>
<path class="middle" d="M10 20 L 30 20" stroke-width="2" stroke="black" fill="transparent"/>
<path class="bottom" d="M10 30 L 30 30" stroke-width="2" stroke="black" fill="transparent"/>
</svg>

Related

Dripping SVG clip-path on animation

In the following example, I apply a clip-path and animate a block in that path to simulate pouring. The issue is, while it looks like it's rendering well in Safari, we can see the box boundaries of the animated path in Chrome. Any idea why, and how to get rid of them?
.fill {
animation-name: fillAction;
animation-iteration-count: 1;
animation-timing-function: cubic-bezier(.2, .6, .8, .4);
animation-duration: 4s;
animation-fill-mode: forwards;
}
#waveShape {
animation-name: waveAction;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: 2s;
fill: #300f0f;
}
#keyframes fillAction {
0% {
transform: translate(0, 700px);
}
100% {
transform: translate(0, 250px);
}
}
#keyframes waveAction {
0% {
transform: translate(380px, 0);
}
100% {
transform: translate(-235px, 0);
}
}
<svg class="h-full w-full" viewBox="0 0 1500 1500">
<defs>
<clipPath id="drop">
<path d="M 537.5,714.5 C 744.168,714.167 950.834,714.5 1157.5,715.5C 1170.62,825.317 1137.29,918.15 1057.5,994C 970.54,1067.47 871.54,1090.14 760.5,1062C 667.845,1033.01 601.012,974.512 560,886.5C 536.431,831.281 528.931,773.948 537.5,714.5 Z" />
</clipPath>
</defs>
<g clip-path="url(#drop)">
<g class="fill">
<path
id="waveShape"
d="M 265.5,488.5 C 265.897,487.475 266.563,487.308 267.5,488C 266.906,488.464 266.239,488.631 265.5,488.5 Z M 888.5,488.5 C 888.897,487.475 889.563,487.308 890.5,488C 889.906,488.464 889.239,488.631 888.5,488.5 Z M 248.5,490.5 C 258.172,490.334 267.839,490.5 277.5,491C 292.931,492.686 308.264,495.019 323.5,498C 340.141,499.478 356.808,499.811 373.5,499C 407.587,492.498 441.92,490.831 476.5,494C 502.019,497.965 527.686,500.132 553.5,500.5C 564.855,500.46 576.188,499.96 587.5,499C 618.82,494.292 650.32,492.126 682,492.5C 705.194,492.581 728.36,493.414 751.5,495C 769.224,497.858 787.058,499.692 805,500.5C 827.502,499.666 849.668,496.5 871.5,491C 884.529,490.231 897.529,490.564 910.5,492C 922.5,494 934.5,496 946.5,498C 963.141,499.478 979.808,499.811 996.5,499C 1030.59,492.498 1064.92,490.831 1099.5,494C 1125.02,497.965 1150.69,500.132 1176.5,500.5C 1187.86,500.46 1199.19,499.96 1210.5,499C 1259.65,492.451 1308.99,490.784 1358.5,494C 1371.26,494.455 1383.93,495.788 1396.5,498C 1395.48,498.519 1394.82,499.353 1394.5,500.5C 1395.5,753.146 1395.83,1005.81 1395.5,1258.5C 978.833,1258.5 562.167,1258.5 145.5,1258.5C 145.5,1004.83 145.5,751.167 145.5,497.5C 180.445,502.459 214.778,500.126 248.5,490.5 Z"
/>
</g>
</g>
</svg>
As a possible solution you can use a mask instead:
.fill {
animation-name: fillAction;
animation-iteration-count: 1;
animation-timing-function: cubic-bezier(.2, .6, .8, .4);
animation-duration: 4s;
animation-fill-mode: forwards;
}
#waveShape {
animation-name: waveAction;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: 2s;
fill: #300f0f;
}
#keyframes fillAction {
0% {
transform: translate(0, 700px);
}
100% {
transform: translate(0, 250px);
}
}
#keyframes waveAction {
0% {
transform: translate(380px, 0);
}
100% {
transform: translate(-235px, 0);
}
}
<svg class="h-full w-full" viewBox="0 500 1500 1000">
<defs>
<mask id="drop">
<rect y="500" width="1500" height="1000" />
<path d="M 537.5,714.5 C 744.168,714.167 950.834,714.5 1157.5,715.5C 1170.62,825.317 1137.29,918.15 1057.5,994C 970.54,1067.47 871.54,1090.14 760.5,1062C 667.845,1033.01 601.012,974.512 560,886.5C 536.431,831.281 528.931,773.948 537.5,714.5 Z" fill="white" />
</mask>
</defs>
<g mask="url(#drop)">
<g class="fill">
<path
id="waveShape"
d="M 265.5,488.5 C 265.897,487.475 266.563,487.308 267.5,488C 266.906,488.464 266.239,488.631 265.5,488.5 Z M 888.5,488.5 C 888.897,487.475 889.563,487.308 890.5,488C 889.906,488.464 889.239,488.631 888.5,488.5 Z M 248.5,490.5 C 258.172,490.334 267.839,490.5 277.5,491C 292.931,492.686 308.264,495.019 323.5,498C 340.141,499.478 356.808,499.811 373.5,499C 407.587,492.498 441.92,490.831 476.5,494C 502.019,497.965 527.686,500.132 553.5,500.5C 564.855,500.46 576.188,499.96 587.5,499C 618.82,494.292 650.32,492.126 682,492.5C 705.194,492.581 728.36,493.414 751.5,495C 769.224,497.858 787.058,499.692 805,500.5C 827.502,499.666 849.668,496.5 871.5,491C 884.529,490.231 897.529,490.564 910.5,492C 922.5,494 934.5,496 946.5,498C 963.141,499.478 979.808,499.811 996.5,499C 1030.59,492.498 1064.92,490.831 1099.5,494C 1125.02,497.965 1150.69,500.132 1176.5,500.5C 1187.86,500.46 1199.19,499.96 1210.5,499C 1259.65,492.451 1308.99,490.784 1358.5,494C 1371.26,494.455 1383.93,495.788 1396.5,498C 1395.48,498.519 1394.82,499.353 1394.5,500.5C 1395.5,753.146 1395.83,1005.81 1395.5,1258.5C 978.833,1258.5 562.167,1258.5 145.5,1258.5C 145.5,1004.83 145.5,751.167 145.5,497.5C 180.445,502.459 214.778,500.126 248.5,490.5 Z"
/>
</g>
</g>
</svg>
I've changed the viewBox of the svg element because I wanted the animation in the view but you can change it back to what you want.

Animating SVG fill linearly along length of path

I have an SVG file that represents a thin shape. I would like to craft an animation such that the entire shape appears be being drawn out.
Example of what I am talking about with the 'S' logo from the Samsung Galaxy S brand:
https://codepen.io/anon/pen/MGawzy
Animation code (because StackOverflow forces me to include it):
#keyframes test {
0% {
clip-path: inset(0px 0px 300px 0px);
}
80% {
clip-path: inset(0px 0px 0px 0px);
}
100% {
clip-path: inset(0px 0px 0px 0px);
}
}
svg {
animation: test;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
A simple SVG in the example above is easy to animate, I can just slowly un-crop the SVG from top-down. But if I have a very complex shape which cannot be animated in this manner (maybe the red line in NASA's logo: https://upload.wikimedia.org/wikipedia/commons/e/e5/NASA_logo.svg), I need a better solution.
Just to clarify again, I do not want to animate the stroke. I want to be able to animate the fill, like it is begin drawn out.
Is there any general solution to this? If there is no general solution, how would I go about key-framing this on my own in a reasonable amount of time?
EDIT: To give some insight, I'm trying to animate the treble clef: https://upload.wikimedia.org/wikipedia/commons/e/e8/G-clef.svg
You could do this (easier to describe than to do, there's a lot of fiddly work involved):
Draw a smooth path on top of the shape that follows what you would consider the "path" and select such a stroke-width that the path covers the shape everywhere.
I would leave the final dot completely out of this, as it is so much thicker than the rest.
Divide the path in such a way that it has no overlapping parts. Order the parts in drawing order, make sure every partial path is drawn in the right direction.
Now divide the shape in the same way, making sure each part is exactly beneath the path on top.
Associate each of the shapes with one of the paths on top, defining the path as a mask for the shape. The path must have stroke:white. Preserve order.
Now you can animate the paths that define the masks with a stroke-dashoffset animation.
I would simply hide the final dot until the pseudo-line animation finishes and then reveal it at once.
Edit: I've definitely got too much time on my hands today, here's the working result:
.clef {
fill: black;
stroke: black;
stroke-width: 0.1;
}
mask path {
fill: none;
stroke: white;
stroke-width: 6;
}
#mask1 path {
stroke-dasharray: 100.8186 100.8186;
stroke-dashoffset: 100.8186;
animation: draw1 1s linear forwards;
}
#keyframes draw1 {
from { stroke-dashoffset: 100.8186; }
to { stroke-dashoffset: 0; }
}
#mask2 path {
stroke-dasharray: 83.6713 83.6713;
stroke-dashoffset: 83.6713;
animation: draw2 1s 1s linear forwards;
}
#keyframes draw2 {
from { stroke-dashoffset: 83.6713; }
to { stroke-dashoffset: 0; }
}
.dot {
opacity: 0;
animation: reveal 0s 2.5s forwards;
}
#keyframes reveal {
from { opacity: 0; }
to { opacity: 1; }
}
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="200" viewBox="0 0 44 75">
<defs>
<mask id="mask1" maskUnits="userSpaceOnUse">
<path d="M 24.3018,49.658 C 15.0191,46.9092 18.5393,38.1126 25.6256,38.2163 35.5458,38.3614 34.8431,54.3874 22.6943,54.1023 12.0123,53.8516 7.34095,40.0402 18.4391,30.1787 29.5373,20.3173 29.9235,12.5622 27.8005,9.28112" />
</mask>
<mask id="mask2" maskUnits="userSpaceOnUse">
<path d="M 27.8005,9.28112 C 25.1382,5.16638 17.6602,8.86888 20.5194,22.1412 L 28.1788,57.6956 C 31.6264,73.699 16.4903,72.3627 15.035,62.329" />
</mask>
</defs>
<path class="clef" mask="url(#mask1)" d="M 26.8522,9.90048 C 26.912,9.95039 26.9649,10.0085 27.0101,10.075 27.4815,10.7683 28.6214,14.0098 25.3767,19.8157 22.846,24.3437 11.0718,30.2815 10.2077,40.9075 9.45969,50.1477 19.1325,56.9723 27.4811,54.2894 33.0239,52.5081 35.8812,44.0959 32.4504,39.7568 23.3964,28.3057 8.87616,45.8309 22.9422,50.6319 21.4126,49.4286 20.37,48.4968 20.1759,47.3578 18.286,36.2692 34.9591,39.1968 30.4666,49.7165 28.6194,54.0421 21.1577,54.879 16.9085,51.0198 13.3489,47.787 11.7693,41.5593 15.7305,37.0885 21.0956,31.0332 27.4302,25.5974 29.1125,17.3081 29.7841,13.9988 29.4887,10.9357 28.6445,8.70078 Z" />
<path class="clef" mask="url(#mask2)" d="M 15.7311,63.3465 C 15.3353,65.46 17.5402,69.8491 21.9764,69.9924 27.3392,70.1658 30.7655,66.0634 29.1692,59.3682 L 21.164,22.4229 C 20.2111,18.0249 20.9262,15.6394 21.4351,14.2178 22.7185,10.6326 25.8192,9.03863 26.8522,9.90048 L 28.6445,8.70078 C 26.9883,4.31578 23.2199,3.11893 20.4997,9.50576 19.1217,12.7412 18.6085,15.989 19.9279,22.2128 L 27.9268,59.9444 C 28.4995,62.6457 28.1161,66.3629 25.595,68.0714 24.3461,68.9177 19.9267,69.5001 18.8455,67.48" />
<path class="clef dot" d="M 15.6702,63.6634 A 3.77139,3.8362 1.075 0 1 19.5129,59.8986 3.77139,3.8362 1.075 0 1 23.2116,63.8049 3.77139,3.8362 1.075 0 1 19.3689,67.5697 3.77139,3.8362 1.075 0 1 15.6702,63.6634 Z" />
</svg>
SVG solution
In this example, solutions from the #ccprog response are used, but the animation is moved from the CSS rules directly to the SVG animation commands
The commands that implement the animation are the same for all patches. The difference in the numeric value of the stroke-dasharray and stroke-dashoffset attributes for each patch:
<animate attributeName="stroke-dashoffset" dur="1s" values="100.8186;0" fill="freeze" />
The animation command for the appearance of a dot on the end of a treble clef:
<animate attributeName="opacity" dur="0.05s" values="0;1" begin="an2.end-0.05s" fill="freeze" />
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="200" viewBox="0 0 44 75">
<defs>
<mask id="mask1" maskUnits="userSpaceOnUse">
<path fill="none" stroke="white" stroke-width="6" stroke-dasharray="100.8186" stroke-dashoffset="100.8186" d="M 24.3018,49.658 C 15.0191,46.9092 18.5393,38.1126 25.6256,38.2163 35.5458,38.3614 34.8431,54.3874 22.6943,54.1023 12.0123,53.8516 7.34095,40.0402 18.4391,30.1787 29.5373,20.3173 29.9235,12.5622 27.8005,9.28112">
<animate attributeName="stroke-dashoffset" dur="1s" values="100.8186;0" fill="freeze"/>
</path>
</mask>
<mask id="mask2" maskUnits="userSpaceOnUse">
<path fill="none" stroke="white" stroke-width="6" stroke-dasharray="83.6713" stroke-dashoffset="83.6713" d="M 27.8005,9.28112 C 25.1382,5.16638 17.6602,8.86888 20.5194,22.1412 L 28.1788,57.6956 C 31.6264,73.699 16.4903,72.3627 15.035,62.329" >
<animate id="an2" attributeName="stroke-dashoffset" dur="1s" values="83.6713;0" begin="+1s" fill="freeze"/>
</path>
</mask>
</defs>
<path class="clef" fill="black" stroke="black" stroke-width="0.1" mask="url(#mask1)" d="M 26.8522,9.90048 C 26.912,9.95039 26.9649,10.0085 27.0101,10.075 27.4815,10.7683 28.6214,14.0098 25.3767,19.8157 22.846,24.3437 11.0718,30.2815 10.2077,40.9075 9.45969,50.1477 19.1325,56.9723 27.4811,54.2894 33.0239,52.5081 35.8812,44.0959 32.4504,39.7568 23.3964,28.3057 8.87616,45.8309 22.9422,50.6319 21.4126,49.4286 20.37,48.4968 20.1759,47.3578 18.286,36.2692 34.9591,39.1968 30.4666,49.7165 28.6194,54.0421 21.1577,54.879 16.9085,51.0198 13.3489,47.787 11.7693,41.5593 15.7305,37.0885 21.0956,31.0332 27.4302,25.5974 29.1125,17.3081 29.7841,13.9988 29.4887,10.9357 28.6445,8.70078 Z"/>
<path class="clef" fill="black" stroke="black" stroke-width="0.1" mask="url(#mask2)" d="M 15.7311,63.3465 C 15.3353,65.46 17.5402,69.8491 21.9764,69.9924 27.3392,70.1658 30.7655,66.0634 29.1692,59.3682 L 21.164,22.4229 C 20.2111,18.0249 20.9262,15.6394 21.4351,14.2178 22.7185,10.6326 25.8192,9.03863 26.8522,9.90048 L 28.6445,8.70078 C 26.9883,4.31578 23.2199,3.11893 20.4997,9.50576 19.1217,12.7412 18.6085,15.989 19.9279,22.2128 L 27.9268,59.9444 C 28.4995,62.6457 28.1161,66.3629 25.595,68.0714 24.3461,68.9177 19.9267,69.5001 18.8455,67.48"/>
<path class="clef dot" opacity="0" d="M 15.6702,63.6634 A 3.77139,3.8362 1.075 0 1 19.5129,59.8986 3.77139,3.8362 1.075 0 1 23.2116,63.8049 3.77139,3.8362 1.075 0 1 19.3689,67.5697 3.77139,3.8362 1.075 0 1 15.6702,63.6634 Z">
<animate attributeName="opacity" dur="0.05s" values="0;1" begin="an2.end-0.05s" fill="freeze"/>
</path>
</svg>
Update 2020
SMIL SVG does not work in IE - caniuse

SVG line animation not working

I am trying to create an effect where smoke comes out of a vessel
Like this example where smoke comes out of a coffee cup but I am not able to do it.
Here's a jsfiddle showing my attempt:
SVG code is:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="150px" height="127px" viewBox="0 0 150 127" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 40.1 (33804) - http://www.bohemiancoding.com/sketch -->
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Mobile-Portrait" transform="translate(-98.000000, -419.000000)" fill="#FFFFFF">
<g id="food_loading" transform="translate(98.000000, 419.000000)">
<path d="M139.06,95.2449167 C134.53,70.4159167 113.7925,50.6875833 87.3925,45.9089167 C87.435,45.5355833 87.5,45.1599167 87.5,44.7889167 C87.5,38.3559167 81.8925,33.12225 75,33.12225 C68.1075,33.12225 62.5,38.3559167 62.5,44.7889167 C62.5,45.1599167 62.5625,45.5355833 62.6075,45.9089167 C36.2075,50.6875833 15.47,70.4159167 10.94,95.2449167 C5.715,98.00525 0,102.067583 0,106.624583 C0,118.489583 38.78,126.457917 75,126.457917 C111.22,126.457917 150,118.489583 150,106.624583 C150,102.067583 144.285,98.00525 139.06,95.2449167 L139.06,95.2449167 L139.06,95.2449167 L139.06,95.2449167 L139.06,95.2449167 L139.06,95.2449167 Z M67.515,45.1925833 C67.505,45.05725 67.5,44.9219167 67.5,44.79125 C67.5,40.9319167 70.865,37.79125 75,37.79125 C79.135,37.79125 82.5,40.9319167 82.5,44.79125 C82.5,44.92425 82.495,45.05725 82.485,45.1925833 C82.3675,45.1809167 82.25,45.17625 82.135,45.1645833 C81.275,45.0759167 80.41,45.0129167 79.54,44.9569167 C79.22,44.9359167 78.9025,44.9055833 78.5825,44.88925 C77.3975,44.8285833 76.205,44.7935833 75.0025,44.7935833 C73.8,44.7935833 72.6075,44.8285833 71.4225,44.88925 C71.1025,44.9055833 70.785,44.9359167 70.465,44.9569167 C69.595,45.0129167 68.73,45.07825 67.87,45.1645833 C67.75,45.17625 67.6325,45.1785833 67.515,45.1925833 L67.515,45.1925833 L67.515,45.1925833 L67.515,45.1925833 L67.515,45.1925833 L67.515,45.1925833 Z M63.3625,59.9859167 C63.545,59.9859167 63.73,59.96725 63.915,59.9299167 C67.51,59.1739167 71.2275,58.79125 74.9675,58.79125 L75,58.79125 C76.38,58.79125 77.5,57.74825 77.5,56.46025 C77.5,55.1699167 76.3825,54.1245833 75,54.1245833 L74.965,54.1245833 C70.8575,54.1245833 66.77,54.5469167 62.815,55.3775833 C61.4675,55.6599167 60.6225,56.90825 60.925,58.1659167 C61.19,59.2509167 62.22,59.9859167 63.3625,59.9859167 L63.3625,59.9859167 L63.3625,59.9859167 L63.3625,59.9859167 L63.3625,59.9859167 L63.3625,59.9859167 Z M24.5525,98.41825 C24.705,98.44625 24.855,98.4579167 25.0025,98.4579167 C26.1875,98.4579167 27.24,97.66925 27.46,96.5445833 C30.0575,83.24925 38.6425,71.41925 50.425,64.9045833 C51.6125,64.2489167 52.005,62.81625 51.3025,61.7079167 C50.5975,60.5995833 49.065,60.23325 47.8775,60.8889167 C34.8675,68.0825833 25.3975,81.0979167 22.5425,95.7045833 C22.2925,96.9739167 23.1925,98.18725 24.5525,98.41825 L24.5525,98.41825 L24.5525,98.41825 L24.5525,98.41825 L24.5525,98.41825 L24.5525,98.41825 Z M65.9975,50.0879167 C67.34,49.90125 68.69,49.7659167 70.045,49.66325 C70.3225,49.64225 70.6,49.6235833 70.8775,49.6049167 C73.6225,49.43225 76.38,49.43225 79.125,49.6049167 C79.4025,49.6235833 79.68,49.64225 79.9575,49.66325 C81.3125,49.7659167 82.6625,49.90125 84.005,50.0879167 C110.05,53.7629167 130.6475,73.1225833 134.385,97.4919167 C134.5,98.2409167 134.5925,98.99225 134.675,99.7435833 C134.7025,100.002583 134.74,100.25925 134.765,100.51825 C134.8625,101.551917 134.935,102.585583 134.97,103.61925 C95.695,112.114917 54.31,112.114917 15.035,103.61925 C15.0725,102.585583 15.1425,101.551917 15.24,100.51825 C15.265,100.25925 15.3,100.002583 15.33,99.7435833 C15.4125,98.9899167 15.505,98.2385833 15.62,97.4919167 C19.355,73.1225833 39.9525,53.7605833 65.9975,50.0879167 L65.9975,50.0879167 L65.9975,50.0879167 L65.9975,50.0879167 L65.9975,50.0879167 L65.9975,50.0879167 Z M75,121.79125 C32.26,121.79125 5,111.83025 5,106.624583 C5,105.730917 6.185,103.761583 10.16,101.192583 C10.15,101.325583 10.155,101.45625 10.145,101.58925 C10.06,102.867917 10,104.155917 10,105.457917 L10,107.296583 L11.9175,107.72825 C32.5525,112.34825 53.7775,114.662917 75,114.662917 C96.2225,114.662917 117.4475,112.350583 138.0825,107.72825 L140,107.296583 L140,105.457917 C140,104.155917 139.94,102.87025 139.855,101.58925 C139.845,101.45625 139.85,101.325583 139.84,101.192583 C143.815,103.761583 145,105.730917 145,106.624583 C145,111.83025 117.74,121.79125 75,121.79125 L75,121.79125 L75,121.79125 L75,121.79125 L75,121.79125 L75,121.79125 Z"
id="food"></path>
<path d="M73.375,27.77425 C73.8625,28.22925 74.5025,28.4579167 75.1425,28.4579167 C75.7825,28.4579167 76.4225,28.22925 76.91,27.77425 C77.8875,26.8619167 77.8875,25.38725 76.91,24.4749167 C74.3725,22.10425 74.3725,18.2495833 76.91,15.8789167 C79.085,13.8489167 80.285,11.1515833 80.285,8.28158333 C80.285,5.41158333 79.0875,2.71425 76.91,0.68425 C75.9325,-0.228083333 74.3525,-0.228083333 73.375,0.68425 C72.3975,1.59658333 72.3975,3.07125 73.375,3.98358333 C74.605,5.13158333 75.285,6.65758333 75.285,8.28158333 C75.285,9.90558333 74.6075,11.4315833 73.375,12.5795833 C68.8875,16.7679167 68.8875,23.5859167 73.375,27.77425 L73.375,27.77425 L73.375,27.77425 L73.375,27.77425 L73.375,27.77425 L73.375,27.77425 Z"
id="food-path" class="food-path" fill="#FFFFFF" stroke="#000000" stroke-width="4"></path>
<path d="M100.875,41.77425 C101.3625,42.22925 102.0025,42.4579167 102.6425,42.4579167 C103.2825,42.4579167 103.9225,42.22925 104.41,41.77425 C105.3875,40.8619167 105.3875,39.38725 104.41,38.4749167 C101.8725,36.10425 101.8725,32.2495833 104.41,29.8789167 C106.585,27.8489167 107.785,25.1515833 107.785,22.2815833 C107.785,19.4115833 106.5875,16.71425 104.41,14.68425 C103.4325,13.7719167 101.8525,13.7719167 100.875,14.68425 C99.8975,15.5965833 99.8975,17.07125 100.875,17.9835833 C102.105,19.1315833 102.785,20.6575833 102.785,22.2815833 C102.785,23.9055833 102.1075,25.4315833 100.875,26.5795833 C96.3875,30.7679167 96.3875,37.5859167 100.875,41.77425 L100.875,41.77425 L100.875,41.77425 L100.875,41.77425 L100.875,41.77425 L100.875,41.77425 Z"
id="food-path" class="food-path" fill="#FFFFFF" stroke="#000000" stroke-width="4"></path>
<path d="M45.875,41.77425 C46.3625,42.22925 47.0025,42.4579167 47.6425,42.4579167 C48.2825,42.4579167 48.9225,42.22925 49.41,41.77425 C50.3875,40.8619167 50.3875,39.38725 49.41,38.4749167 C46.8725,36.10425 46.8725,32.2495833 49.41,29.8789167 C51.585,27.8489167 52.785,25.1515833 52.785,22.2815833 C52.785,19.4115833 51.5875,16.71425 49.41,14.68425 C48.4325,13.7719167 46.8525,13.7719167 45.875,14.68425 C44.8975,15.5965833 44.8975,17.07125 45.875,17.9835833 C47.105,19.1315833 47.785,20.6575833 47.785,22.2815833 C47.785,23.9055833 47.1075,25.4315833 45.875,26.5795833 C41.3875,30.7679167 41.3875,37.5859167 45.875,41.77425 L45.875,41.77425 L45.875,41.77425 L45.875,41.77425 L45.875,41.77425 L45.875,41.77425 Z"
id="food-path" class="food-path" fill="#FFFFFF" stroke="#000000" stroke-width="4"></path>
</g>
</g>
</g>
</svg>
Css is:
.food-path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 1.5s linear alternate infinite;
}
#keyframes dash {
from {
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 0;
}
}
For the dash offset line drawing trick to work, you need to have a "line" consisting of just a stroke. Your steam lines are actually closed shapes, where the path runs around the outside of the line. So instead of getting the steam effect you want, you are going to get an animated line that runs around the outside of the steam line.
What you have now is this:
.food-path {
stroke-dasharray: 69;
stroke-dashoffset: 69;
animation: dash 1.5s linear alternate infinite;
}
#keyframes dash {
from {
stroke-dashoffset: 69;
}
to {
stroke-dashoffset: 0;
}
}
<svg width="400px" height="400px" viewBox="20 0 60 60">
<path d="M45.875,41.77425 C46.3625,42.22925 47.0025,42.4579167 47.6425,42.4579167 C48.2825,42.4579167 48.9225,42.22925 49.41,41.77425 C50.3875,40.8619167 50.3875,39.38725 49.41,38.4749167 C46.8725,36.10425 46.8725,32.2495833 49.41,29.8789167 C51.585,27.8489167 52.785,25.1515833 52.785,22.2815833 C52.785,19.4115833 51.5875,16.71425 49.41,14.68425 C48.4325,13.7719167 46.8525,13.7719167 45.875,14.68425 C44.8975,15.5965833 44.8975,17.07125 45.875,17.9835833 C47.105,19.1315833 47.785,20.6575833 47.785,22.2815833 C47.785,23.9055833 47.1075,25.4315833 45.875,26.5795833 C41.3875,30.7679167 41.3875,37.5859167 45.875,41.77425 L45.875,41.77425 L45.875,41.77425 L45.875,41.77425 L45.875,41.77425 L45.875,41.77425 Z" id="food-path" class="food-path" fill="#FFFFFF" stroke="#000000" stroke-width="1"></path>
</svg>
First you will need to load your SVG into an editor and redraw those steam lines as a single thick squiggly line.
What you want in your drawing is more like this:
.food-path {
stroke-dasharray: 31;
stroke-dashoffset: 31;
animation: dash 1s linear alternate infinite;
}
#keyframes dash {
from {
stroke-dashoffset: 31;
}
to {
stroke-dashoffset: 0;
}
}
<svg width="400px" height="400px" viewBox="20 0 60 60">
<path d="M 49.41,41.77425 C50.3875,40.8619167 50.3875,39.38725 49.41,38.4749167 C46.8725,36.10425 46.8725,32.2495833 49.41,29.8789167 C51.585,27.8489167 52.785,25.1515833 52.785,22.2815833 C52.785,19.4115833 51.5875,16.71425 49.41,14.68425" id="food-path" class="food-path" fill="#FFFFFF" stroke="#000000" stroke-width="1"></path>
</svg>
Secondly, to get the drawing effect to work, you need to use values for the dash array and dash offset that correspond to the length of your line. The "1000" you are using is way too long for the lines you are using. See the values I am using in my examples.
The case is to properly adjust values for stroke-dasharray and stroke-dashoffset. You could do that with JS - it's quite easy way to read the actual lengths. stroke-dasharray lets you specify the length of the rendered part of the line, then the length of the gap. stroke-dashoffset lets you change where the dasharray starts.
With some experiment you can also get nice effect without JS. Here is your corrected version:
http://codepen.io/MakiBM/pen/NRaRWO
body {
background-color: lightgray;
}
svg {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
.food-path {
stroke-dasharray: 100;
stroke-dashoffset: 0;
animation: dash 3000ms linear infinite;
}
#keyframes dash {
from {
stroke-dashoffset: 200;
}
to {
stroke-dashoffset: 0;
}
}
For a more reusable solution see the link:
https://jakearchibald.com/2013/animated-line-drawing-svg/

How to animate handwriting text on the web page using SVG?

I am trying to animate a text that I created and saved as SVG. So far, I've only been able to animate the stroke, but that's not what I am trying to achieve. How can I implement animation like the two examples, below?
http://codepen.io/se7ensky/pen/waoMyx
https://codepen.io/munkholm/pen/EaZJQE
Here is what I have so far:
.test {
width: 300px
/* margin:0 auto; */
}
.l1 {
animation: dash 15s 1;
stroke-linecap: round;
stroke-miterlimit: 10;
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation-fill-mode: forwards;
/*fill: none;*/
}
.l2 {
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: dash 20s linear forwards;
-webkit-animation-delay: 1s;
/* Chrome, Safari, Opera */
animation-delay: 1s;
}
.l3 {
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: dash 25s linear forwards;
-webkit-animation-delay: 2.5s;
/* Chrome, Safari, Opera */
animation-delay: 2.5s;
}
.l4 {
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: dash 25s linear forwards;
-webkit-animation-delay: 4.5s;
/* Chrome, Safari, Opera */
animation-delay: 4.5s;
}
#keyframes dash {
to {
stroke-dashoffset: 0;
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg class="test" 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 30.1 21.8" style="enable-background:new 0 0 30.1 21.8;" xml:space="preserve">
<g>
<path class="text l1" d="M16.5,9.2c-0.2-0.2-0.2-1,0.1-1.5c0.1-0.1,0.2-0.3,0.3-0.4c-1.6,0-3.2-0.3-4.7-0.1C10.8,7.3,9.5,8,9.3,8.9
c-0.1,0.6,0.5,0.8,0.7,1c0.1,0.1,0,0.2-0.1,0.1C9.5,10,8.7,9.4,9,8.7c0,0,0-0.1,0-0.2c0.3-1.2,1.7-1.8,3.3-1.9
c1.8-0.1,3.9,0.4,4.8,0.4c0.2-0.2,0.4-0.4,0.5-0.4c0.3-0.1,0.6,0.1,0.3,0.4c-0.1,0.1-0.4,0.3-0.6,0.5c-0.4,0.4-0.8,1-0.5,1.5
C16.8,9.2,16.7,9.3,16.5,9.2z M12.1,12.8c0.1,0.1-0.1,0.3-0.1,0.3c-0.2,0.3-0.5,0.8-0.8,0.8c-0.1,0-0.5-0.1-0.5-0.1
c-0.1-0.8,1.5-3.5,1.9-4.2c0.2-0.3,0.1-0.4,0.1-0.5c0.1-0.4,0.9-1.4,1.5-1.4c0.2,0,0.8,0.2,0.7,0.5c0,0-0.1-0.1-0.2-0.1
c-1.1,0-2.9,3.6-3.4,4.7c-0.3,0.7,0.1,0.6,0.4,0.3C11.8,13,12,12.8,12.1,12.8z" fill="red" stroke="#000" stroke-miterlimit="10" stroke-width="0.5" />
<path class="text l2" d="M14.4,12.3c-0.2,0-0.3-0.2-0.1-0.2c0.4,0,1.1-0.4,1.5-0.8c0.2-0.2,0.6-0.5,0.5-0.8c0-0.3-0.4-0.2-0.6-0.1
c-0.7,0.3-1.7,1.3-2,2.2c-0.3,1,0.6,1,1.4,0.7c0.9-0.4,1.7-1,2.1-1.7c0-0.1,0.1-0.1,0.1,0c0.1,0,0.1,0.1,0,0.1
c-0.5,0.8-1.2,1.5-2.1,1.8c-1.2,0.5-2.8,0-2.1-1.5c0.4-0.8,2.2-2.4,3.1-2.1c0.5,0.2,0.4,0.8,0.2,1.1C16.1,11.8,15,12.2,14.4,12.3z" fill="none" stroke="#000" stroke-miterlimit="5" stroke-width="0.5"
/>
<path class="text l3" d="M17.3,13.6c-0.2,0.2-0.1,0.5,0.4,0.4c0.6-0.2,1.5-0.9,1.5-1.6c0-0.3-0.7-0.6-0.9-0.7c-0.2-0.1-0.3-0.3-0.4-0.4
c-0.1,0.2-0.3,0.5-0.5,0.8c-0.1,0.1-0.3,0-0.2-0.1c0.3-0.5,0.6-0.9,0.6-1.1c0.1-0.9,1.7-1.7,2.6-1.7c0.5,0,1,0.3,0.7,0.8
c-0.1,0.2-0.2,0.3-0.4,0.4c-0.1,0-0.2,0-0.1-0.2c0.2-0.2,0.3-0.6,0-0.6c-0.4,0-1,0.2-1.3,0.4c-0.4,0.2-0.7,0.4-1,0.9
c-0.3,0.3-0.2,0.6,0.1,0.8c0.8,0.5,1.8,0.8,0.9,1.8c-0.4,0.5-1.1,0.7-1.7,0.9c-0.2,0-0.7,0.1-0.9-0.1c-0.1-0.1,0-0.3,0.2-0.5
c0.1-0.1,0.3-0.3,0.6-0.3c0.1,0,0.1,0.1,0,0.1C17.5,13.4,17.3,13.5,17.3,13.6z" fill="none" stroke="#000" stroke-miterlimit="5" stroke-width="0.5"/>
<path class="text l4" d="M23.6,10.2c-0.2,0.1-0.8,0.1-1.4,0.2c-0.2,0.3-0.3,0.5-0.3,0.6c-0.4,0.7-0.7,1.4-0.7,1.7c-0.1,0.5,0.2,0.8,0.6,0.6
c0.4-0.2,1.3-1,1.8-1.7c0.1-0.1,0.2,0,0.1,0.1c-0.2,0.4-1,1.2-1.6,1.6c-0.4,0.3-1.3,0.6-1.5-0.1c-0.1-0.3,0.1-0.9,0.4-1.5
c-0.1,0.1-0.2,0.3-0.5,0.6c-0.1,0.1-0.2,0-0.1-0.2c0.4-0.5,0.7-1,0.9-1.2c0,0,0.1-0.2,0.3-0.5c-0.1,0-0.2,0-0.3,0
c-0.1,0-0.2-0.1-0.2-0.3c0.1-0.2,0.4-0.2,0.6-0.2c0,0,0,0,0,0l0.6-1.1c0.3-0.5,0.3-0.6,0.5-0.7c0.2,0,0.4,0,0.5,0.1
c0.1,0.1,0,0.4-0.1,0.5C23.2,9,23.1,9,23,9.1l-0.6,1l0.2,0c0.4,0,0.7-0.1,1.1-0.1C23.9,10,24.1,10.1,23.6,10.2z" fill="none" stroke="#000" stroke-miterlimit="5" stroke-width="0.5"/>
</g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
</svg>
View on CodePen
How the Se7ensky animation works is that it uses the standard dash animation technique, but clips the animated stroke with an outline representing the hand-drawn look of the logo.
So the standard dash animation technique works as follows. You take a standard line:
<svg>
<path d="M 10,75 L 290,75" stroke="red" stroke-width="50"/>
</svg>
Then you add a dash pattern to it and animate it's position (stroke-dashoffset).
.pen {
stroke-dasharray: 280 280;
stroke-dashoffset: 280;
animation-duration: 2s;
animation-name: draw;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: linear;
}
#keyframes draw {
from {
stroke-dashoffset: 280;
}
to {
stroke-dashoffset: 0;
}
}
<svg>
<path class="pen" d="M 10,75 L 290,75" stroke="red" stroke-width="50"/>
</svg>
Finally to get the fancy variable stroke width of the Se7ensky example, you clip that line with the outline of your logo.
So let's pretend this simple path below represents your logo:
<svg>
<path stroke="black" stroke-width="1" fill="lightgrey"
d="M 40,50
C 110,55 195,60, 265,55
C 290,55 290,85 265,85
C 195,85 110,85 40,100
C 0,100 0,50 40,50 Z"/>
</svg>
We turn that into a clipPath element and use it to trim our animated stroke to the shape of our logo:
.pen {
stroke-dasharray: 280 280;
stroke-dashoffset: 280;
animation-duration: 2s;
animation-name: draw;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: linear;
}
#keyframes draw {
from {
stroke-dashoffset: 280;
}
to {
stroke-dashoffset: 0;
}
}
<svg>
<clipPath id="logo">
<path d="M 40,50
C 110,55 195,60, 265,55
C 290,55 290,85 265,85
C 195,85 110,85 40,100
C 0,100 0,50 40,50 Z"/>
</clipPath>
<path class="pen" d="M 10,75 L 290,75" stroke="red" stroke-width="50" clip-path="url(#logo)"/>
</svg>
So to replicate their example, you'll need to add a continuous path (or paths if you want) to your SVG that represents the path that a pen would take if it were writing the letters in your logo.
Then animate that path using the dashoffset technique while clipping it with your original logo.
Update
Here's a final demo with a more realistic letter shape:
// Simple code to enable and disable the clipping path
var chk = document.getElementById("chk");
var penpath = document.getElementById("penpath");
chk.addEventListener("input", function(evt) {
if (evt.target.checked) {
penpath.classList.add("clipped");
} else {
penpath.classList.remove("clipped");
}
});
.pen {
fill: none;
stroke: red;
stroke-width: 18;
stroke-linecap: round;
stroke-dasharray: 206 206;
stroke-dashoffset: 206;
animation-duration: 2s;
animation-name: draw;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: linear;
}
.clipped {
clip-path: url(#logo);
}
#keyframes draw {
from {
stroke-dashoffset: 206;
}
to {
stroke-dashoffset: 0;
}
}
<svg>
<defs>
<clipPath id="logo">
<path d="m85.77 49.77c-10.59 8.017-27.38 21.95-41.58 21.95-6.396 0-12.99-2.481-12.39-9.735l0.3998-4.199c38.38-12.03 48.17-26.15 48.17-35.5 0-7.635-7.995-9.162-14.39-9.162-25.98-0.1909-54.97 25.39-54.17 50.39 0.3998 12.6 7.196 25.01 21.79 25.01 19.79 0 41.78-17.94 53.97-31.5zm-52.37-1.336c5.397-12.6 16.99-21.76 26.98-24.24 1.399-0.3818 2.399 0.7635 2.399 2.1 0.1999 3.245-11.79 16.42-29.38 22.14z"/>
</clipPath>
</defs>
<path id="penpath" d="m39.02 51.1c5.361-1.771 10.04-4.182 15.98-7.857 6.019-3.933 9.841-7.728 12.77-10.71 1.403-1.369 12.03-15.97-7.857-13.93-9.824 1.01-19.62 8.3-26.16 14.91-6.538 6.61-10.42 14.51-11.96 22.23-2.559 12.76 1.807 26.19 21.07 23.48 13.96-1.965 32.59-14.55 43.66-25.54" class="pen clipped"/>
</svg>
<p>
<input id="chk" type="checkbox" checked="true"/> <label for="chk">Enable clipping path</label>
</p>
The example looks like a combination of svg paths and delayed animations.
This blog post by CSS-Tricks explains it pretty well (Note that the svg must have strokes for this to work):
https://css-tricks.com/svg-line-animation-works/
Here's a guide on stroke-dashoffset (used on the example) that might be useful:
https://css-tricks.com/almanac/properties/s/stroke-dashoffset/

Change direction of SVG animation

I saw this SVG animation and I'm wondering how to alter the direction that the line is erased in; currently the line retracts from the last point it is drawn, however I want the reverse; for the line to erase itself from the point where it first started to draw (so that it looks more like a loading animation).
I see that the animation property on .path has a value of infinite, but I'm not sure how the direction is specified.
The HTML is
<div class="bg">
<svg xmlns="http://www.w3.org/2000/svg" width="670" height="236" viewBox="0 0 670 236">
<path class="path" stroke="#4CADC1" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="300" stroke-dashoffset="300" fill="none" d="M343.6 75.9v20.3l23.1 21.8-23.1 21.8v20.3l44.6-42.1zM326.4 139.8l-23.1-21.8 23.1-21.8v-20.3l-44.6 42.1 44.6 42.1z"/>
<path class="path" stroke="#4CADC1" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="500" stroke-dashoffset="500" fill="none" d="M335 38.9c-43.7 0-79.1 35.4-79.1 79.1s35.4 79.1 79.1 79.1 79.1-35.4 79.1-79.1-35.4-79.1-79.1-79.1zM335 182.9c-35.8 0-64.9-29.1-64.9-64.9s29.1-64.9 64.9-64.9 64.9 29.1 64.9 64.9-29.1 64.9-64.9 64.9z"/>
</svg>
</div>
And the CSS is
body {
background-color: #fff;
}
.bg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.path {
animation: draw 3.5s infinite;
}
#keyframes draw {
50% {
stroke-dashoffset: 0;
}
}
I like your idea of making this an loading animation:
CODEPEN
Now what i did:
changed the animation start stop point
#keyframes draw {
100% {
stroke-dashoffset: -500;
}
}
Why -500?
Because this is the value of the dash-array.
This is defined in the <svg>: dasharray="500"
Changed this value in the inner most path. It was only 300
I added a linear animation
animation: draw 5s infinite linear;
The default is ease. I found the animation has better consistency with a linear animation.
NOTE
dashoffset=500 <- makes the animation start without the dash/stroke
I used the negative value for stroke-dashoffset that Persijn recommended. This worked great in Chrome and FF, but it didn't work properly in Safari.
I've found that if you open the SVG in Illustrator, you can reverse the direction of the path, by opening the Attributes panel (you might have to click the "show more" in the top right) and literally clicking the "reverse path" button.
stroke-dasharray can be a list of white space separated dashes and gaps, so you could do something like this:
var svgPath = document.getElementById('svgPath');
var pathLength = svgPath.getTotalLength();
var offset = 0;
function offsetPath() {
requestAnimationFrame(offsetPath);
offset += 0.1;
var dasharray = 0 + ' ' + offset + ' ' + (pathLength - offset);
svgPath.setAttribute('stroke-dasharray', dasharray);
}
requestAnimationFrame(offsetPath);
<svg xmlns="http://www.w3.org/2000/svg" width="670" height="236" viewBox="0 0 670 236">
<path id="svgPath" class="path" stroke="#4CADC1" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="100 100 100" fill="none" d="M343.6 75.9v20.3l23.1 21.8-23.1 21.8v20.3l44.6-42.1zM326.4 139.8l-23.1-21.8 23.1-21.8v-20.3l-44.6 42.1 44.6 42.1z"
/>
</svg>
Changing SVG Line Animation Direction
Add KeyFrames and Classes for Both Directions:
.dash {
stroke-dasharray : 10 5;
animation : dash 4s linear infinite;
}
.dash_reverse {
stroke-dasharray : 10 5;
animation : dash_reverse 4s linear infinite;
}
#keyframes dash {
to {
stroke-dashoffset: 100;
}
}
#keyframes dash_reverse {
to {
stroke-dashoffset: -100;
}
}
Use JavaScript to Toggle Animation:
function animate_line_forward(id) {
$("#" + id).removeClass("dash_reverse");
$("#" + id).addClass("dash");
}
function animate_line_reverse(id) {
$("#" + id).removeClass("dash");
$("#" + id).addClass("dash_reverse");
}
Call functions as needed (pass the SVG line id into the above functions:
Calling animate_line_forward:
Calling animate_line_reverse:

Resources