CSS animation rotate then wiggle SVG - css

I have an SVG compass with an arrow in it. I want to be able to add a class to the arrow and have it rotate a certain degree then stay there and wiggle.
I have the rotation and wiggle working just not together. Not sure how to combine the two so they work together. Here is my code:
div {
max-width: 40%;
}
.st0 {
fill: none;
stroke: #505050;
stroke-width: 4.11;
stroke-linecap: round;
stroke-miterlimit: 10;
}
.st1 {
fill: none;
stroke: #808080;
stroke-width: 2.57;
stroke-linecap: round;
stroke-miterlimit: 10;
}
.st2 {
fill: #505050;
}
.st3 {
opacity: 0.5;
}
.st4 {
fill: none;
}
/* Fill Colors */
.green {
fill: rgba(21, 255, 0, 0.5);
}
.dgreen {
fill: rgba(12, 140, 0, 0.5);
}
.red {
fill: rgba(255, 42, 0, 0.5);
}
.dred {
fill: rgba(140, 23, 0, 0.5);
}
/* Arrow */
#arrow {
transform-origin: 50% 59.7%;
animation-name: wiggle;
animation-duration: 1s;
animation-fill-mode: forward;
-webkit-animation-fill-mode: forward;
-webkit-animation-iteration-count: infinite;
/* Safari 4.0 - 8.0 */
animation-iteration-count: infinite;
}
/* Rotations */
.north#arrow {
-webkit-transform: rotate(45deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.northEast#arrow {
-webkit-transform: rotate(90deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.west#arrow {
-webkit-transform: rotate(135deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.southWest#arrow {
-webkit-transform: rotate(180deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.south#arrow {
-webkit-transform: rotate(225deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.southWest#arrow {
-webkit-transform: rotate(270deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.west#arrow {
-webkit-transform: rotate(315deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.northWest#arrow {
-webkit-transform: rotate(0deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
/* Wiggle Animation */
/* safari and chrome */
#-webkit-keyframes wiggle {
0% {
-webkit-transform: rotate(4deg);
}
50% {
-webkit-transform: rotate(-4deg);
}
100% {
-webkit-transform: rotate(4deg);
}
}
/* firefox */
#-moz-keyframes wiggle {
0% {
-moz-transform: rotate(4deg);
}
50% {
-moz-transform: rotate(-4deg);
}
100% {
-moz-transform: rotate(4deg);
}
}
#keyframes wiggle {
0% {
transform: rotate(4deg);
}
50% {
transform: rotate(-4deg);
}
100% {
transform: rotate(4deg);
}
}
<div>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 116.3 144" style="enable-background:new 0 0 116.3 144;" xml:space="preserve">
<title>compass</title>
<line id="N" class="st0" x1="58.2" y1="31.3" x2="58.2" y2="49.6"/>
<line id="NW" class="st1" x1="18.5" y1="46.1" x2="31.4" y2="59"/>
<line id="W" class="st0" x1="3.6" y1="85.7" x2="21.9" y2="85.7"/>
<line id="SW" class="st1" x1="18.3" y1="125.5" x2="31.3" y2="112.5"/>
<line id="S" class="st0" x1="58" y1="140.3" x2="58" y2="122"/>
<line id="SE" class="st1" x1="97.7" y1="125.6" x2="84.8" y2="112.6"/>
<line id="E" class="st0" x1="113.4" y1="85.9" x2="95.1" y2="85.9"/>
<line id="NE" class="st1" x1="97.8" y1="46.2" x2="84.9" y2="59.1"/>
<path id="compass" class="st2" d="M69.6,28.8c6.7-6.3,7-16.9,0.7-23.6s-16.9-7-23.6-0.7s-7,16.9-0.7,23.6c0.2,0.2,0.4,0.5,0.7,0.7
c-31.5,6.3-51.9,37-45.6,68.5s37,51.9,68.5,45.6c31.5-6.3,51.9-37,45.6-68.5C110.6,51.4,92.6,33.4,69.6,28.8z M58.2,6.5
c5.6,0,10.2,4.6,10.2,10.2H48C48,11.1,52.6,6.5,58.2,6.5z M58.2,138.3c-29,0-52.5-23.5-52.5-52.5s23.5-52.5,52.5-52.5
c29,0,52.5,23.5,52.5,52.5c0,0,0,0,0,0C110.6,114.8,87.1,138.3,58.2,138.3z"/>
<path id="inner_compass" class="st2" d="M58.2,130.8c-24.9,0-45.2-20.2-45.2-45.2s20.2-45.2,45.2-45.2c24.9,0,45.2,20.2,45.2,45.1
c0,0,0,0,0,0C103.3,110.6,83.1,130.8,58.2,130.8z M58.2,43.8c-23.1,0-41.9,18.8-41.9,41.9s18.8,41.9,41.9,41.9s41.9-18.8,41.9-41.9
C100.1,62.6,81.3,43.8,58.2,43.8L58.2,43.8z"/>
<g id="NNW" class="st3">
<path id="nnwPie" class="st4 green" d="M57.9,27.7v58.2l-41-41C27.8,33.9,42.5,27.7,57.9,27.7z"/>
</g>
<g id="WNW" class="st3">
<path id="wnwPie" class="st4 dgreen" d="M57.9,85.8H0.2v-0.2c0-15.3,6-30,16.8-40.8L57.9,85.8z"/>
</g>
<g id="WSW">
<path id="wswPie" class="st4" d="M57.9,85.8l-40.8,40.8c-10.8-10.8-16.9-25.5-17-40.8H57.9z"/>
</g>
<g id="SSW">
<path id="sswPie" class="st4" d="M57.9,85.8v57.8c-15.3,0-30-6.2-40.8-17L57.9,85.8z"/>
</g>
<g id="SSE">
<path id="ssePie" class="st4 red" d="M99,126.9c-10.8,10.8-25.5,16.8-40.8,16.8H58V85.8L99,126.9z"/>
</g>
<g id="ESE">
<path id="esePie" class="st4 dred" d="M116.2,85.8c0,15.4-6.2,30.2-17.2,41l-41-41H116.2z"/>
</g>
<g id="ENE">
<path id="enePie" class="st4" d="M116.2,85.7v0.2H57.9l41.2-41.2C110.1,55.5,116.2,70.3,116.2,85.7z"/>
</g>
<g id="NNE">
<path id="nnePie" class="st4" d="M99.1,44.6L57.9,85.8V27.7h0.2C73.5,27.6,88.3,33.7,99.1,44.6z"/>
</g>
<polygon id="arrow" class="st2 west" points="78.4,105.3 80.2,107.1 79.1,108.3 77.2,106.4 75.5,109.7 74.1,108.6 75.9,105.1 75.1,104.3
73.3,107.7 71.9,106.6 73.8,103 72.9,102.1 71.2,105.6 69.8,104.5 71.7,100.9 63.5,92.7 63.5,92.7 41.5,70.7 41.4,70.8 39,74.3
34.5,62.5 46.3,67.1 42.5,69.5 64.6,91.6 65.2,92.1 72.9,99.8 76.5,98 77.6,99.5 74.1,101.1 74.9,101.9 78.6,100 79.7,101.4
76.2,103.1 75.9,102.9 77.1,104 80.8,102.3 81.9,103.8 "/>
</svg>
</div>

You need to chain animations together and use a delay between them so one plays after the other has finished.
You were previously using a transition and then an animation which are two separate things. Also browser prefixes are now pretty redundant for animations, I personally would use the non-prefixed syntax.
Here is one example where the arrow moves to the south and then wiggles, you will need to add in the others:
Example CSS
.wrap:hover #arrow {
transform-origin: 50% 59.7%;
animation-name: spinSouth, wiggleSouth;
animation-delay: 0s, 1s;
animation-duration: 1s, 1s;
animation-iteration-count: 1, infinite;
}
/* Spin south Animation */
#keyframes spinSouth {
0% {
transform: rotate(4deg);
}
100% {
transform: rotate(225deg);
}
}
/* Wiggle Animation */
#keyframes wiggleSouth {
0% {
transform: rotate(225deg);
}
50% {
transform: rotate(220deg);
}
100% {
transform: rotate(225deg);
}
}
Fiddle:
http://jsfiddle.net/5cn9sm99/

I think this may be a shorter solution with the code you already have. You could wrap your arrow in an arrow container like this:
<g id="arrowContainer">
<polygon id="arrow" class="st2 west" points="78.4,105.3 80.2,107.1 79.1,108.3 77.2,106.4 75.5,109.7 74.1,108.6 75.9,105.1 75.1,104.3
73.3,107.7 71.9,106.6 73.8,103 72.9,102.1 71.2,105.6 69.8,104.5 71.7,100.9 63.5,92.7 63.5,92.7 41.5,70.7 41.4,70.8 39,74.3
34.5,62.5 46.3,67.1 42.5,69.5 64.6,91.6 65.2,92.1 72.9,99.8 76.5,98 77.6,99.5 74.1,101.1 74.9,101.9 78.6,100 79.7,101.4
76.2,103.1 75.9,102.9 77.1,104 80.8,102.3 81.9,103.8 "/>
</g>
Then add this styles to center the pivot point of the container:
#arrowContainer{ transform-origin: 50% 50%; }
Now replace the Rotations to target the arrowContainer and use Javascript or jQuery to add the classes you already created. Here is the full code.
var changeDirection = function changeClass(myClass){
$('#compass').attr("class", myClass);
}
div {
max-width: 300px;
}
.st0 {
fill: none;
stroke: #505050;
stroke-width: 4.11;
stroke-linecap: round;
stroke-miterlimit: 10;
}
.st1 {
fill: none;
stroke: #808080;
stroke-width: 2.57;
stroke-linecap: round;
stroke-miterlimit: 10;
}
.st2 {
fill: #505050;
}
.st3 {
opacity: 0.5;
}
.st4 {
fill: none;
}
/* Fill Colors */
.green {
fill: rgba(21, 255, 0, 0.5);
}
.dgreen {
fill: rgba(12, 140, 0, 0.5);
}
.red {
fill: rgba(255, 42, 0, 0.5);
}
.dred {
fill: rgba(140, 23, 0, 0.5);
}
/* Arrow */
#arrowContainer{
transform-origin: 50% 50%;
}
#arrow {
transform-origin: 50% 59.7%;
animation-name: wiggle;
animation-duration: 1s;
animation-fill-mode: forward;
-webkit-animation-fill-mode: forward;
-webkit-animation-iteration-count: infinite;
/* Safari 4.0 - 8.0 */
animation-iteration-count: infinite;
}
/* Rotations */
.north #arrowContainer {
-webkit-transform: rotate(45deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.northEast #arrowContainer {
-webkit-transform: rotate(90deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.east #arrowContainer {
-webkit-transform: rotate(135deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.southEast #arrowContainer {
-webkit-transform: rotate(180deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.south #arrowContainer {
-webkit-transform: rotate(225deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.southWest #arrowContainer {
-webkit-transform: rotate(270deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.west #arrowContainer {
-webkit-transform: rotate(315deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
.northWest #arrowContainer {
-webkit-transform: rotate(0deg);
-webkit-transition: -webkit-transform 0.5s ease-in;
}
/* Wiggle Animation */
/* safari and chrome */
#-webkit-keyframes compass {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(0deg);
}
}
#-webkit-keyframes wiggle {
0% {
-webkit-transform: rotate(4deg);
}
50% {
-webkit-transform: rotate(-4deg);
}
100% {
-webkit-transform: rotate(4deg);
}
}
/* firefox */
#-moz-keyframes wiggle {
0% {
-moz-transform: rotate(4deg);
}
50% {
-moz-transform: rotate(-4deg);
}
100% {
-moz-transform: rotate(4deg);
}
}
#keyframes wiggle {
0% {
transform: rotate(4deg);
}
50% {
transform: rotate(-4deg);
}
100% {
transform: rotate(4deg);
}
}
/* Button Styles */
.buttons{
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="buttons">
<button onclick="changeDirection('north')">North</button>
<button onclick="changeDirection('northEast')">NorthEast</button>
<button onclick="changeDirection('east')">East</button>
<button onclick="changeDirection('southEast')">South East</button>
<button onclick="changeDirection('south')">South</button>
<button onclick="changeDirection('southWest')">South West</button>
<button onclick="changeDirection('west')">West</button>
<button onclick="changeDirection('northWest')">North West</button>
</div>
<div id="compass" class="addClassHere">
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 116.3 144" style="enable-background:new 0 0 116.3 144;" xml:space="preserve">
<title>compass</title>
<line id="N" class="st0" x1="58.2" y1="31.3" x2="58.2" y2="49.6"/>
<line id="NW" class="st1" x1="18.5" y1="46.1" x2="31.4" y2="59"/>
<line id="W" class="st0" x1="3.6" y1="85.7" x2="21.9" y2="85.7"/>
<line id="SW" class="st1" x1="18.3" y1="125.5" x2="31.3" y2="112.5"/>
<line id="S" class="st0" x1="58" y1="140.3" x2="58" y2="122"/>
<line id="SE" class="st1" x1="97.7" y1="125.6" x2="84.8" y2="112.6"/>
<line id="E" class="st0" x1="113.4" y1="85.9" x2="95.1" y2="85.9"/>
<line id="NE" class="st1" x1="97.8" y1="46.2" x2="84.9" y2="59.1"/>
<path id="compass" class="st2" d="M69.6,28.8c6.7-6.3,7-16.9,0.7-23.6s-16.9-7-23.6-0.7s-7,16.9-0.7,23.6c0.2,0.2,0.4,0.5,0.7,0.7
c-31.5,6.3-51.9,37-45.6,68.5s37,51.9,68.5,45.6c31.5-6.3,51.9-37,45.6-68.5C110.6,51.4,92.6,33.4,69.6,28.8z M58.2,6.5
c5.6,0,10.2,4.6,10.2,10.2H48C48,11.1,52.6,6.5,58.2,6.5z M58.2,138.3c-29,0-52.5-23.5-52.5-52.5s23.5-52.5,52.5-52.5
c29,0,52.5,23.5,52.5,52.5c0,0,0,0,0,0C110.6,114.8,87.1,138.3,58.2,138.3z"/>
<path id="inner_compass" class="st2" d="M58.2,130.8c-24.9,0-45.2-20.2-45.2-45.2s20.2-45.2,45.2-45.2c24.9,0,45.2,20.2,45.2,45.1
c0,0,0,0,0,0C103.3,110.6,83.1,130.8,58.2,130.8z M58.2,43.8c-23.1,0-41.9,18.8-41.9,41.9s18.8,41.9,41.9,41.9s41.9-18.8,41.9-41.9
C100.1,62.6,81.3,43.8,58.2,43.8L58.2,43.8z"/>
<g id="NNW" class="st3">
<path id="nnwPie" class="st4 green" d="M57.9,27.7v58.2l-41-41C27.8,33.9,42.5,27.7,57.9,27.7z"/>
</g>
<g id="WNW" class="st3">
<path id="wnwPie" class="st4 dgreen" d="M57.9,85.8H0.2v-0.2c0-15.3,6-30,16.8-40.8L57.9,85.8z"/>
</g>
<g id="WSW">
<path id="wswPie" class="st4" d="M57.9,85.8l-40.8,40.8c-10.8-10.8-16.9-25.5-17-40.8H57.9z"/>
</g>
<g id="SSW">
<path id="sswPie" class="st4" d="M57.9,85.8v57.8c-15.3,0-30-6.2-40.8-17L57.9,85.8z"/>
</g>
<g id="SSE">
<path id="ssePie" class="st4 red" d="M99,126.9c-10.8,10.8-25.5,16.8-40.8,16.8H58V85.8L99,126.9z"/>
</g>
<g id="ESE">
<path id="esePie" class="st4 dred" d="M116.2,85.8c0,15.4-6.2,30.2-17.2,41l-41-41H116.2z"/>
</g>
<g id="ENE">
<path id="enePie" class="st4" d="M116.2,85.7v0.2H57.9l41.2-41.2C110.1,55.5,116.2,70.3,116.2,85.7z"/>
</g>
<g id="NNE">
<path id="nnePie" class="st4" d="M99.1,44.6L57.9,85.8V27.7h0.2C73.5,27.6,88.3,33.7,99.1,44.6z"/>
</g>
<g id="arrowContainer">
<polygon id="arrow" class="st2 west" points="78.4,105.3 80.2,107.1 79.1,108.3 77.2,106.4 75.5,109.7 74.1,108.6 75.9,105.1 75.1,104.3
73.3,107.7 71.9,106.6 73.8,103 72.9,102.1 71.2,105.6 69.8,104.5 71.7,100.9 63.5,92.7 63.5,92.7 41.5,70.7 41.4,70.8 39,74.3
34.5,62.5 46.3,67.1 42.5,69.5 64.6,91.6 65.2,92.1 72.9,99.8 76.5,98 77.6,99.5 74.1,101.1 74.9,101.9 78.6,100 79.7,101.4
76.2,103.1 75.9,102.9 77.1,104 80.8,102.3 81.9,103.8 "/>
</g>
</svg>
</div>

Related

SVG stroke appearing only during css animation

I'm trying to figure out why there's a line in this SVG animation that I'm trying to make. But it's only an effect of animating it with css, and it's not part of the SVG itself. It seems to be some stroke but stroke: none doesn't affect it.
image showing the stroke
https://jsfiddle.net/bgu2e7pn/
PS: I would also appreciate if you can point out how to have the full width of the coffee content svg exceed the cup width so it looks more seamless.
You can work around this bug by using a mask instead of a clip-path.
body {
background: grey;
}
#coffee-cup .fill {
animation-name: coffeeFill;
animation-iteration-count: 1;
animation-timing-function: cubic-bezier(.2, .6, .8, .4);
animation-duration: 4s;
animation-fill-mode: forwards;
}
#coffee-cup #waveShape {
animation-name: waveMotion;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: 0.5s;
fill: #8C5926;
stroke: #3D2518;
stroke-width: 10px;
}
#keyframes coffeeFill {
0% {
transform: translate(0, 150px);
}
100% {
transform: translate(0, -15px);
}
}
#keyframes waveMotion {
0% {
transform: translate(-150px, 0);
}
100% {
transform: translate(0, 0);
}
}
<div id="coffee-cup">
<div>
<svg class="position-absolute" width="259" height="180" viewBox="0 0 259 180" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M259 0H53L55.8218 23.0874C24.0777 28.8271 0 56.6017 0 90C0 127.555 30.4446 158 68 158C69.4425 158 70.8746 157.955 72.2948 157.867L75 180H238L259 0ZM57.7548 38.9028L70.4677 142.918C69.4854 142.972 68.496 143 67.5 143C38.5051 143 15 119.495 15 90.5C15 64.835 33.4162 43.4713 57.7548 38.9028Z"
fill="white" fill-opacity="0.7" />
<mask id="coffee">
<rect width="100%" height="100%" fill="black"/>
<path d="M70 49H244L232.139 156H82.2489L70 49Z" fill="white" />
</mask>
<g mask="url(#coffee)">
<g class="fill">
<path 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>
</svg>

Chain keyframes animations

Hello I'am trying to chain two animations.
Now what happens is that after moveUp finished, my triangle jump back to place and then starts scaleDown. Why triangle jumps back when i specify forwards parametr which tells it should stop at last keyframes option.
I have no idea what goes wrong here.
#bottom-rect {
animation: moveUp 2s forwards, scaleDown 1s 1s forwards;
}
#keyframes moveUp {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-25%);
}
}
#keyframes scaleDown {
0% {
transform: scaleY(1);
transform-origin: center;
transform-box: fill-box;
}
100% {
transform: scaleY(0);
transform-origin: center;
transform-box: fill-box;
}
}
<svg width="135" height="216" viewBox="0 0 135 216" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="svg">
<path id="bottom-rect" d="M81.2 216V189L54 216H81.2Z" fill="black"/>
<path id="top-rect" d="M54.2 0V27L81 0H54.2Z" fill="black"/>
<path id="Vector" d="M0 162H36L135 54H99L0 162Z" fill="black"/>
</g>
</svg>
The effect i need to achieve is basically this: 0sec (moveUp starts) -> 1sec (scaleDown starts) -> 2s both finished.
It's actually possible to do additive animations in CSS. In this case you can just add an element around your path tag. So with an svg we can add an additional g tag that I will name animation2 in my example.
#bottom-rect {
animation: scaleDown 1s 1s forwards;
}
#animation2{
animation: moveUp 2s forwards;
}
#keyframes moveUp {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-25%);
}
}
#keyframes scaleDown {
0% {
transform: scaleY(1);
transform-origin: center;
transform-box: fill-box;
}
100% {
transform: scaleY(0);
transform-origin: center;
transform-box: fill-box;
}
}
<svg width="135" height="216" viewBox="0 0 135 216" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="svg">
<g id = "animation2">
<path id="bottom-rect" d="M81.2 216V189L54 216H81.2Z" fill="black"/>
</g>
<path id="top-rect" d="M54.2 0V27L81 0H54.2Z" fill="black"/>
<path id="Vector" d="M0 162H36L135 54H99L0 162Z" fill="black"/>
</g>
</svg>

How to add background colors to pattern fills?

How do I convert this code so that the path with id #wires has the color #000 initially and then being colored by the pattern and keyframes as oppossed to no color at all? So essentially the star should be black and the gradient animation will creep up the star. How do I achieve this?
This was inspired by https://stackoverflow.com/a/42032657/5586359.
.fill {
animation-name: fillAction;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(.26, .64, .8, .4);
animation-duration: 4s;
animation-fill-mode: forwards;
}
#waveShape {
animation-name: waveAction;
animation-iteration-count: infinite;
animation-timing-function: ease-out;
animation-duration: 0.5s;
width: 100%;
height: 50%;
}
#wires {
fill: url(#waveGradient);
}
svg {
width: 100%;
height: auto;
}
#keyframes fillAction {
0% {
transform: translate(0, 50%);
}
100% {
transform: translate(0, -1.6%);
}
}
#keyframes waveAction {
0% {
transform: translate(-0%, 0);
}
10% {
transform: translate(-5%, 0);
}
20% {
transform: translate(-10%, 0);
}
30% {
transform: translate(-15%, 0);
}
40% {
transform: translate(-20%, 0);
}
50% {
transform: translate(-15%, 0);
}
60% {
transform: translate(-10%, 0);
}
70% {
transform: translate(-5%, 0)
}
100% {
transform: translate(0%, 0);
}
}
<div class="banner">
<?xml version="1.0" standalone="no"?>
<!-- Generator: Gravit.io -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="0 0 250 250" width="250" height="250">
<defs>
<clipPath id="_clipPath_kDqJpeywA1tWpdDxczhcHinYaTsaw8EY"><rect width="250" height="250"/>
</clipPath>
<linearGradient id="gradient">
<stop offset="0%" stop-color="#333291"/>
<stop offset="30%" stop-color="purple"/>
<stop offset="100%" stop-color="#fb5b5d" stop-opacity="100" />
</linearGradient>
<pattern id='waveGradient' width="1" height="1" viewBox="0 0 100 100" preserveAspectRatio="none">
<g class="fill">
<path fill="url(#gradient)" 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>
</pattern>
</defs>
<g clip-path="url(#_clipPath_kDqJpeywA1tWpdDxczhcHinYaTsaw8EY)">
<path id="wires" d="M12.015.624L9.19 9.293H0l7.445 5.384-2.819 8.673L12 17.986l7.422 5.393-2.835-8.713L24 9.292h-9.162L12.015.622v.002z"/>
</g>
</svg>
</div>
One idea is to duplicate the path of the star and you fill it with the color you want. Both will be placed above each other and you will have the visual you want
.fill {
animation-name: fillAction;
animation-iteration-count: infinite;
animation-timing-function: cubic-bezier(.26, .64, .8, .4);
animation-duration: 4s;
animation-fill-mode: forwards;
}
#waveShape {
animation-name: waveAction;
animation-iteration-count: infinite;
animation-timing-function: ease-out;
animation-duration: 0.5s;
width: 100%;
height: 50%;
}
#wires {
fill: url(#waveGradient);
}
#empty {
fill:#000;
}
svg {
width: 100%;
height: auto;
}
#keyframes fillAction {
0% {
transform: translate(0, 50%);
}
100% {
transform: translate(0, -1.6%);
}
}
#keyframes waveAction {
0% {
transform: translate(-0%, 0);
}
10% {
transform: translate(-5%, 0);
}
20% {
transform: translate(-10%, 0);
}
30% {
transform: translate(-15%, 0);
}
40% {
transform: translate(-20%, 0);
}
50% {
transform: translate(-15%, 0);
}
60% {
transform: translate(-10%, 0);
}
70% {
transform: translate(-5%, 0)
}
100% {
transform: translate(0%, 0);
}
}
<div class="banner">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="0 0 250 250" width="250" height="250">
<defs>
<linearGradient id="gradient">
<stop offset="0%" stop-color="#333291"/>
<stop offset="30%" stop-color="purple"/>
<stop offset="100%" stop-color="#fb5b5d" stop-opacity="100" />
</linearGradient>
<pattern id='waveGradient' width="1" height="1" viewBox="0 0 100 100" preserveAspectRatio="none">
<g class="fill">
<path fill="url(#gradient)" 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>
</pattern>
</defs>
<g >
<path id="empty" d="M12.015.624L9.19 9.293H0l7.445 5.384-2.819 8.673L12 17.986l7.422 5.393-2.835-8.713L24 9.292h-9.162L12.015.622v.002z"/>
<path id="wires" d="M12.015.624L9.19 9.293H0l7.445 5.384-2.819 8.673L12 17.986l7.422 5.393-2.835-8.713L24 9.292h-9.162L12.015.622v.002z"/>
</g>
</svg>
</div>

SVG CSS animation after hover off

I tried several ways to svg animation, but i can't do finish animation after hover off. I have seen some hints on stackoverflow, but in my situation it does not work. In my example I have few options animations in keyframes.
https://codepen.io/GuyDiamond/pen/QBpQze
<rect x="0" y="5" width="100" height="100" fill="red" />
<path id="heart" class="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" fill="#fff"/>
<style type="text/css">
svg:hover .heart {
animation-timing-function: ease-in-out;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: rotation;
transition: .5s;
animation-direction: normal;
animation-fill-mode: forwards;
}
#keyframes rotation {
50% {
transform: rotateY(180deg);
opacity:0;
}
60% {
transform: translate(100px, 0);
opacity:0;
}
100% {
transform: translate(0, 0);
opacity:1;
}
}
You can't do what you want with pure CSS. You need to use JS.
Here's one way, using the animationiteration event, which fires each time the animation loop ends.
// Get the SVG DOM object
var mysvg = document.getElementById("mysvg");
var running = false;
// On hover add the "run" class, which makes the animation run
mysvg.addEventListener("mouseenter", function(evt) {
evt.target.classList.add("run");
running = true;
});
// On mouse out, arrange to remove the "run" class when the animation loop ends
mysvg.addEventListener("mouseleave", function(evt) {
running = false;
});
// When animation loop ends, remove the "run" class if we no longer want to continue running
mysvg.addEventListener("animationiteration", function(evt) {
if (!running) {
evt.target.ownerSVGElement.classList.remove("run");
}
});
.box {
width: 300px;
height: 500px;
}
<div class="box">
<svg id="mysvg" width="100%" height="100%" viewBox="-30 0 250 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<rect x="0" y="5" width="100" height="100" fill="red" />
<path id="heart" class="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" fill="#fff"/>
<style type="text/css">
svg .heart {
}
.run .heart {
animation-timing-function: ease-in-out;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: rotation;
animation-direction: normal;
animation-fill-mode: forwards;
}
#keyframes rotation {
50% {
transform: rotateY(180deg);
opacity:0;
}
60% {
transform: translate(100px, 0);
opacity:0;
}
100% {
transform: translate(0, 0);
opacity:1;
}
}
</style>
</svg>
</div>
You mean the animation ends suddenly? That's because you've defined the transition in the hover so as soon as the hover ends there's no active transition any more.
.box {
width: 300px;
height: 500px;
}
<div class="box">
<svg width="100%" height="100%" viewBox="-30 0 250 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<rect x="0" y="5" width="100" height="100" fill="red" />
<path id="heart" class="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" fill="#fff"/>
<style type="text/css">
svg .heart {
transition: .5s;
}
svg:hover .heart {
animation-timing-function: ease-in-out;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: rotation;
animation-direction: normal;
animation-fill-mode: forwards; }
#keyframes rotation {
50% {
transform: rotateY(180deg);
opacity:0;
}
60% {
transform: translate(100px, 0);
opacity:0;
}
100% {
transform: translate(0, 0);
opacity:1;
}
}
</style>
</svg>
</div>
By changing the animation-play-state on hover I think it could work
https://codepen.io/dok/pen/ZjKGRE
svg #heart {
animation-timing-function: ease-in-out;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: rotation;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: paused;
}
svg .heart:hover #heart {
animation-play-state: running;
}

Reverse animation of SVG elements

I'm working on an animation which will be triggered when a class is added with jQuery after a click event.
It has the be something like a toggle:
After first click on button, animation 1 will be run https://codepen.io/thijs-webber/pen/dMBKRp
After second click on same button reversed animation needs to be run
Is there a way to reverse the chain of animations easily?
.animation-container {
width: 250px;
position: relative;
margin: 0 auto;
margin-top: 50px;
}
.dot-pink-light {
fill: #CE97AE;
}
.dot-pink {
fill: #D82566;
}
.dot-green-light {
fill: #AFBF99;
}
.dot-green {
fill: #77BC1F;
}
/* ANIMATIONS */
#keyframes rotate_clockwise {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
}
#keyframes rotate_anticlockwise {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
}
}
#keyframes scale_down {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
100% {
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
}
#keyframes pop_out_dots_top {
100% {
transform: translate(0px, -80px);
}
}
#keyframes pop_out_dots_bottom {
100% {
transform: translate(0px, 80px);
}
}
/* 1 */
.container.opened {
animation: scale_down 250ms ease;
transform-origin: 50% 50% 0;
}
/* 2 */
.container.opened .groups .extra-dot-top {
animation: pop_out_dots_top 250ms ease;
-webkit-animation-delay: 250ms;
animation-delay: 250ms;
transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
animation: pop_out_dots_bottom 250ms ease;
-webkit-animation-delay: 250ms;
animation-delay: 250ms;
transform-origin: 50% 50% 0;
}
.container.opened .groups .group-2 {
animation: rotate_anticlockwise 250ms ease;
transform-origin: 50% 50% 0;
-webkit-animation-delay: 250ms;
animation-delay: 250ms;
}
/* 4 */
.container.opened .groups {
animation: rotate_clockwise 250ms ease;
transform-origin: 50% 50% 0;
-webkit-animation-delay: 500ms;
animation-delay: 500ms;
}
<div class="animation-container">
<div class="col-xs-12">
<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">
<!-- Group 1 -->
<g class="container opened">
<g class="groups">
<g class="group-1 pink">
<circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
<circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
<circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
<circle class="dot-pink" cx="100" cy="100" r="21.4" />
<circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
</g>
<!-- Group 2 -->
<g class="group-2 green">
<circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
<circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
<circle class="dot-green" cx="100" cy="21.4" r="21.4" />
<circle class="dot-green" cx="100" cy="100" r="21.4" />
<circle class="dot-green" cx="100" cy="178.6" r="21.4" />
</g>
</g>
</g>
</svg>
</div>
</div>
Since you are looking for a toggle effect with only two distinct states, it is much better for you to use transitions instead of animations. Transitions can automatically produce the reverse effect when the class is removed.
Demo with transitions:
window.onload = function() {
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
document.querySelector('.container').classList.toggle('opened');
});
}
.animation-container {
width: 250px;
position: relative;
margin: 0 auto;
margin-top: 50px;
}
.dot-pink-light {
fill: #CE97AE;
}
.dot-pink {
fill: #D82566;
}
.dot-green-light {
fill: #AFBF99;
}
.dot-green {
fill: #77BC1F;
}
/* 1 */
.container {
transform: scale(1);
transition: transform 2.5s ease;
transform-origin: 50% 50% 0;
transition-delay: 5s;
}
.container.opened {
transform: scale(0.5);
transition-delay: 0s;
}
.container .groups .extra-dot-top {
transform: translate(0px, 0px);
transition: transform 2.5s ease;
transition-delay: 2.5s;
transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-top {
transform: translate(0px, -80px);
}
.container .groups .extra-dot-bottom {
transform: translate(0px, 0px);
transition: transform 2.5s ease;
transition-delay: 2.5s;
transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
transform: translate(0px, 80px);
}
.container .groups .group-2 {
transform: rotate(0deg);
transition: transform 2.5s ease;
transform-origin: 50% 50% 0;
transition-delay: 2.5s;
}
.container.opened .groups .group-2 {
transform: rotate(-90deg);
}
/* 4 */
.container .groups {
transform: rotate(0deg);
transition: transform 2.5s ease;
transform-origin: 50% 50% 0;
}
.container.opened .groups {
transform: rotate(45deg);
transition-delay: 5s;
}
<div class="animation-container">
<div class="col-xs-12">
<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">
<!-- Group 1 -->
<g class="container">
<g class="groups">
<g class="group-1 pink">
<circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
<circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
<circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
<circle class="dot-pink" cx="100" cy="100" r="21.4" />
<circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
</g>
<!-- Group 2 -->
<g class="group-2 green">
<circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
<circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
<circle class="dot-green" cx="100" cy="21.4" r="21.4" />
<circle class="dot-green" cx="100" cy="100" r="21.4" />
<circle class="dot-green" cx="100" cy="178.6" r="21.4" />
</g>
</g>
</g>
</svg>
</div>
</div>
<button>Click</button>
Animations on the other hand cannot automatically produce the reverse effect and code needs to be written. Even when the reverse animation's code is written, getting it work is complex (and cannot be done with pure CSS) because you will have to remove the "open" animation before adding the "close" animation and when the happens the element(s) will immediately snap to their original position before executing the reverse effect. The output wouldn't be as graceful as with transitions unless you put in a lot of messy code.
Demo with animations:
window.onload = function() {
var btn = document.querySelector('button');
var container = document.querySelector('.container');
var groups = document.querySelector('.groups');
var group2 = document.querySelector('.group-2');
var extradtG = document.querySelector('.green .extra-dot-top');
var extradtP = document.querySelector('.pink .extra-dot-top');
var extradbG = document.querySelector('.green .extra-dot-bottom');
var extradbP = document.querySelector('.pink .extra-dot-bottom');
var opened = false;
btn.addEventListener('click', function() {
if (opened) {
container.style.transform = 'scale(1)';
extradtG.style.transform = 'translate( 0px, 0px)';
extradtP.style.transform = 'translate( 0px, 0px)';
extradbG.style.transform = 'translate( 0px, 0px)';
extradbP.style.transform = 'translate( 0px, 0px)';
group2.style.transform = 'rotate(0deg);'
groups.style.transform = 'rotate(0deg)';
container.classList.remove('opened');
container.clientHeight; // dummy call
container.classList.add('closed');
} else {
container.style.transform = 'scale(0.5)';
extradtG.style.transform = 'translate( 0px, -80px)';
extradtP.style.transform = 'translate( 0px, -80px)';
extradbG.style.transform = 'translate( 0px, 80px)';
extradbP.style.transform = 'translate( 0px, 80px)';
group2.style.transform = 'rotate(-90deg);'
groups.style.transform = 'rotate(45deg)';
container.classList.remove('closed');
container.clientHeight; // dummy call
container.classList.add('opened');
}
opened = !opened;
});
}
.animation-container {
width: 250px;
position: relative;
margin: 0 auto;
margin-top: 50px;
}
.dot-pink-light {
fill: #CE97AE;
}
.dot-pink {
fill: #D82566;
}
.dot-green-light {
fill: #AFBF99;
}
.dot-green {
fill: #77BC1F;
}
/* ANIMATIONS */
#keyframes rotate_clockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(45deg);
}
}
#keyframes rotate_anticlockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-90deg);
}
}
#keyframes scale_down {
0% {
transform: scale(1);
}
100% {
transform: scale(0.5);
}
}
#keyframes pop_out_dots_top {
0% {
transform: translate(0px, 0px);
}
100% {
transform: translate(0px, -80px);
}
}
#keyframes pop_out_dots_bottom {
0% {
transform: translate(0px, 0px);
}
100% {
transform: translate(0px, 80px);
}
}
/* 1 */
.container.opened {
animation: scale_down 2.5s ease;
transform-origin: 50% 50% 0;
}
.container.closed {
animation: scale_down 2.5s ease reverse backwards;
transform-origin: 50% 50% 0;
animation-delay: 5s;
}
/* 2 */
.container.opened .groups .extra-dot-top {
animation: pop_out_dots_top 2.5s ease backwards;
animation-delay: 2.5s;
transform-origin: 50% 50% 0;
}
.container.closed .groups .extra-dot-top {
animation: pop_out_dots_top 2.5s ease reverse backwards;
animation-delay: 2.5s;
transform-origin: 50% 50% 0;
}
.container.opened .groups .extra-dot-bottom {
animation: pop_out_dots_bottom 2.5s ease backwards;
animation-delay: 2.5s;
transform-origin: 50% 50% 0;
}
.container.closed .groups .extra-dot-bottom {
animation: pop_out_dots_bottom 2.5s ease reverse backwards;
animation-delay: 2.5s;
transform-origin: 50% 50% 0;
}
.container.opened .groups .group-2 {
animation: rotate_anticlockwise 2.5s ease backwards;
transform-origin: 50% 50% 0;
animation-delay: 2.5s;
}
.container.closed .groups .group-2 {
animation: rotate_anticlockwise 2.5s ease reverse backwards;
transform-origin: 50% 50% 0;
animation-delay: 2.5s;
}
/* 4 */
.container.opened .groups {
animation: rotate_clockwise 2.5s ease backwards;
transform-origin: 50% 50% 0;
animation-delay: 5s;
}
.container.closed .groups {
animation: rotate_clockwise 2.5s ease reverse backwards;
transform-origin: 50% 50% 0;
}
<div class="animation-container">
<div class="col-xs-12">
<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" enable-background="new 0 0 200 200">
<!-- Group 1 -->
<g class="container">
<g class="groups">
<g class="group-1 pink">
<circle class="dot-pink-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
<circle class="dot-pink-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
<circle class="dot-pink" cx="100" cy="21.4" r="21.4" />
<circle class="dot-pink" cx="100" cy="100" r="21.4" />
<circle class="dot-pink" cx="100" cy="178.6" r="21.4" />
</g>
<!-- Group 2 -->
<g class="group-2 green">
<circle class="dot-green-light extra-dot-top" cx="100" cy="21.4" r="21.4" />
<circle class="dot-green-light extra-dot-bottom" cx="100" cy="178.6" r="21.4" />
<circle class="dot-green" cx="100" cy="21.4" r="21.4" />
<circle class="dot-green" cx="100" cy="100" r="21.4" />
<circle class="dot-green" cx="100" cy="178.6" r="21.4" />
</g>
</g>
</g>
</svg>
</div>
</div>
<button>Click</button>
(The animation version has a dummy call container.clientHeight which is done to make sure that there is a repaint between the removal of one animation and addition of another. Else, it would look as though nothing happened. You can find more details in my answer here.)

Resources