SVG Animation - CSS Hover Animation For SVG From The Center - css

I have done this effect in GSAP here is the Codepen as a reference:
https://codepen.io/whitelionx/full/vYGQqBZ
const svgs = document.querySelectorAll("svg");
svgs.forEach((svg) => {
const tl = gsap
.timeline({
defaults: { ease: "power1.in" },
paused: true
})
.to(svg.children[0], { drawSVG: "50% 50%" })
.from(svg.children[1], { drawSVG: "0% 0%" }, 0);
svg.addEventListener("mouseenter", () => tl.play());
svg.addEventListener("mouseleave", () => tl.reverse());
});
Now I wanna do it with CSS solely so that when I hover my svg I get the same effect, here is my code sandbox:
https://codesandbox.io/s/xenodochial-benz-17lss?file=/src/styles.css

I've modified things to animate the stroke-dasharray instead.
body {
background: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-direction: column;
}
svg {
width: 50px;
height: 50px;
margin: 25px;
}
.circle {
stroke-dasharray: 28.3,0,28.3;
transform-origin: 50% 50%;
transform: rotate(180deg);
transition: stroke-dasharray 0.5s linear;
}
.line {
stroke-dasharray: 20;
stroke-dashoffset: 20;
transition: stroke-dashoffset 0.5s linear;
}
svg:hover .circle {
stroke-dasharray: 0,56.0;
}
svg:hover .line {
stroke-dashoffset: 0;
}
<svg
version="1.1"
shape-rendering="auto"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 20 20"
xml:space="preserve">
<path class="circle" fill="none" stroke="#FFFFFF" stroke-miterlimit="10" d="M10,1c5,0,9,4,9,9s-4,9-9,9s-9-4-9-9S5,1,10,1z"/>
<path class="line" fill="none" stroke="#FFFFFF" stroke-miterlimit="10" d="M10,0v20"/>
</svg>

I also did it in the meantime and now I get better understanding of css animations thanks to your answer too :D thinking out of the box
body {
background: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-direction: column;
}
svg {
width: 50px;
height: 50px;
margin: 25px;
cursor: pointer;
}
.circle {
stroke-dasharray: 56.6;
stroke-dashoffset: 0;
transform-origin: 50% 50%;
transition: stroke-dashoffset 0.3s linear, transform 0.3s linear;
}
.line {
stroke-dasharray: 20;
stroke-dashoffset: 20;
transition: stroke-dashoffset 0.3s linear;
}
svg:hover .circle {
stroke-dashoffset: 56.6;
transform: rotate(180deg);
}
svg:hover .line {
stroke-dashoffset: 0;
}
<svg
version="1.1"
shape-rendering="auto"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px"
y="0px"
viewBox="0 0 20 20"
enable-background="new 0 0 20 20"
xml:space="preserve"
>
<path
class="circle"
fill="none"
stroke="#FFFFFF"
stroke-miterlimit="10"
d="M10,1c5,0,9,4,9,9s-4,9-9,9s-9-4-9-9S5,1,10,1z"
></path>
<path
class="line"
fill="none"
stroke="#FFFFFF"
stroke-miterlimit="10"
d="M10,0v20"
></path>
</svg>

Related

Invert the left svg animation?

Here is my code https://codepen.io/victoreugen2002/pen/PoJJPzP
I am trying to animate the left and right svg, to acheive this:
both starting at the same time from the top and they continue drawing.
until they both met at the bottom in the middle.
In order to acheive this I am thinking of inversing the animation for left svg, but it's not working:
.left {
width: 50%;
stroke-dasharray: 1855.968505859375;
animation: dash 2s ease-in;
#keyframes dash {
from {
stroke-dashoffset: 1855.968505859375;
}
to {
stroke-dashoffset: 3710;
}
}
svg {
left: 0;
}
}
You had to go from -1855.968505859375 to 0.
.left {
width: 50%;
stroke-dasharray: 1855.968505859375;
animation: dash-left 2s ease-in;
}
.left svg {
left: 0;
}
.right {
width: 50%;
stroke-dasharray: 1855.968505859375;
animation: dash-right 2s ease-in;
}
.right svg {
right: 0;
}
svg {
position: absolute;
top: 20px;
width: 50%;
stroke-width: 5px;
}
#keyframes dash-left {
from { stroke-dashoffset: -1855.968505859375 }
to { stroke-dashoffset: 0 }
}
#keyframes dash-right {
from { stroke-dashoffset: 1855.968505859375 }
to { stroke-dashoffset: 0 }
}
<div class="left">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 733 425">
<path d="M733,424.5H39A38.5,38.5,0,0,1,.5,386V39A38.5,38.5,0,0,1,39,.5H733" style="fill: none;stroke: #78be21"/>
</svg>
</div>
<div class="right">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 733 425">
<path d="M0,.5H694A38.5,38.5,0,0,1,732.5,39V386A38.5,38.5,0,0,1,694,424.5H0" style="fill: none;stroke: #78be21"/>
</svg>
</div>

SVG animation with CSS onclick

I have a heart button when onclick it will fill the SVG with red from bottom to top and when unclicked it will unfill the SVG from top to bottom. Heres what I've searched so far:JSFiddle
I'm new with this kind of techniques like keyframes and clip-path thing. These can all be done via css only?
body {
display: -webkit-box;
display: flex;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
height: 100vh;
}
.heart-container {
position: relative;
width: 40px;
height: 40px;
}
.heart-clip {
display: block;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
-webkit-clip-path: url(#svgPath);
clip-path: url(#svgPath);
}
.heart-clip:hover {
-webkit-animation: pulse .6s .3s infinite;
animation: pulse .6s .3s infinite;
}
.heart-clip:hover::before {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.heart-clip::before {
content: '';
display: block;
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #D32F2F;
opacity: 0;
-webkit-transform: scale(0);
transform: scale(0);
-webkit-transition: opacity .2s linear, -webkit-transform .2s linear;
transition: opacity .2s linear, -webkit-transform .2s linear;
transition: transform .2s linear, opacity .2s linear;
transition: transform .2s linear, opacity .2s linear, -webkit-transform .2s linear;
-webkit-transform-origin: center 60%;
transform-origin: center 60%;
}
.heart-stroke {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
fill: #D32F2F;
}
#-webkit-keyframes pulse {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
30% {
-webkit-transform: scale(1.2);
transform: scale(1.2);
}
60% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
#keyframes pulse {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
30% {
-webkit-transform: scale(1.2);
transform: scale(1.2);
}
60% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
<svg height="0" width="0">
<defs>
<clipPath id="svgPath">
<path d="M20,35.09,4.55,19.64a8.5,8.5,0,0,1-.13-12l.13-.13a8.72,8.72,0,0,1,12.14,0L20,10.79l3.3-3.3a8.09,8.09,0,0,1,5.83-2.58,8.89,8.89,0,0,1,6.31,2.58,8.5,8.5,0,0,1,.13,12l-.13.13Z"/>
</clipPath>
</defs>
</svg>
<div class="heart-container">
<svg width="40" height="40" viewBox="0 0 40 40" class='heart-stroke'>
<path d="M20,35.07,4.55,19.62a8.5,8.5,0,0,1-.12-12l.12-.12a8.72,8.72,0,0,1,12.14,0L20,10.77l3.3-3.3A8.09,8.09,0,0,1,29.13,4.9a8.89,8.89,0,0,1,6.31,2.58,8.5,8.5,0,0,1,.12,12l-.12.12ZM10.64,7.13A6.44,6.44,0,0,0,6.07,18.19L20,32.06,33.94,18.12A6.44,6.44,0,0,0,34,9l0,0a6.44,6.44,0,0,0-4.77-1.85A6,6,0,0,0,24.83,9L20,13.78,15.21,9A6.44,6.44,0,0,0,10.64,7.13Z"/>
</svg>
<a href='#' class='heart-clip'></a>
</div>
any alternatives and solutions is much appreciated!
Thanks in advance!
Consider filling with color using the feFlood filters and animating with changing thedy attribute of the feoffset filter.
Repeated clicks change the color direction animation
var svg1 = document.getElementById("svg1"),
close = document.getElementById('close'),
open = document.getElementById("open");
let flag = true;
svg1.addEventListener('click', function() {
if (flag == true) {
close.beginElement();
flag = false;
} else {
open.beginElement();
flag = true;
}
});
<div class="heart-container">
<svg id="svg1" width="40" height="40" viewBox="0 0 40 40" class='heart-stroke'>
<defs>
<filter id="red_fill" x="0%" y="0%">
<feFlood flood-color="#ded9d5" />
<feOffset dx="0">
<!-- Animation fills of color from top to bottom. -->
<animate id="close" attributeName="dy" values="0;40" dur="1s" begin="indefinite" repeatCount="3" restart="whenNotActive" fill="freeze"/>
<!-- Animation fills of color from bottom to top. -->
<animate id="open" attributeName="dy" values="40;0" dur="1s" begin="indefinite" repeatCount="3" restart="whenNotActive" fill="freeze"/>
</feOffset>
<feComposite operator="in" in2="SourceGraphic" />
<feComposite operator="over" in2="SourceGraphic" />
</filter>
</defs>
<path filter="url(#red_fill)" stroke="red" stroke-width="2" fill="red" d="M20,35.07,4.55,19.62a8.5,8.5,0,0,1-.12-12l.12-.12a8.72,8.72,0,0,1,12.14,0L20,10.77l3.3-3.3A8.09,8.09,0,0,1,29.13,4.9a8.89,8.89,0,0,1,6.31,2.58,8.5,8.5,0,0,1,.12,12l-.12.12Z"/>
</svg>
<a href='#' class='heart-clip'></a>
</div>

SVG circle with multiple origin for stroke animation

I have a simple donut graph with fill-in animation. The problem is that I get two separate paths. (Es. 10% bar gives me 0-10% and then space and then another 10%.
I have tried playing around with the different variables but I can't figure out what I am doing wrong, any help? I have used this: https://codepen.io/matttherat/pen/EeMaEw?editors=1100
Here's a screen:
.svg-item {
flex: 1;
font-size: 16px;
max-width: 120px;
animation: donutfade 1s;
margin: 0 auto;
}
.data-des {
font-size: 0.7em;
display: block;
font-weight: bold;
text-align: center;
margin-top: 10px;
}
#keyframes donutfade {
/* this applies to the whole svg item wrapper */
0% {
opacity: 0.2;
}
100% {
opacity: 1;
}
}
.donut-ring-ext {
stroke: #50b180;
}
.donut-segment {
transform-origin: center;
}
.donut-segment-2 {
stroke: #a8df8a;
animation: donut1 1s;
}
.donut-segment-3 {
stroke: #a8df8a;
animation: donut2 1s;
}
.donut-segment-4 {
stroke: #a8df8a;
animation: donut3 1s;
}
.donut-percent {
color: #3c8560;
animation: donutfadelong 1s;
}
#keyframes donutfadelong {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#keyframes donut1 {
0% {
stroke-dasharray: 0 100;
}
100% {
stroke-dasharray: 10 90;
}
}
#keyframes donut2 {
0% {
stroke-dasharray: 0, 100;
}
100% {
stroke-dasharray: 20, 80;
}
}
#keyframes donut3 {
0% {
stroke-dasharray: 0, 100;
}
100% {
stroke-dasharray: 50, 50;
}
}
.donut-label {
font-size: 0.28em;
font-weight: 700;
line-height: 1;
fill: #000;
transform: translateY(0.25em);
}
.donut-percent {
font-size: 0.5em;
line-height: 1;
transform: translateY(0.5em);
font-weight: 100;
}
.donut-data {
font-size: 0.12em;
line-height: 1;
transform: translateY(0.5em);
text-align: center;
text-anchor: middle;
color: #666;
fill: #666;
animation: donutfadelong 1s;
}
<div class="svg-item">
<svg width="100%" height="100%" viewBox="0 0 40 40" class="donut">
<circle
class="donut-hole"
cx="20"
cy="20"
r="15.91549430918954"
fill="#fff"
></circle>
<circle
class="donut-ring-ext"
cx="20"
cy="20"
r="19"
fill="transparent"
stroke-width="2"
></circle>
<circle
class="donut-segment donut-segment-2"
cx="20"
cy="20"
r="22"
fill="transparent"
stroke-width="2"
stroke-dasharray="10 90"
stroke-dashoffset="-5"
></circle>
<g class="donut-text donut-text-1">
<text y="50%" transform="translate(0, 2)">
<tspan
x="50%"
text-anchor="middle"
class="donut-percent"
>
10%
</tspan>
</text>
</g>
<span class="data-des">Amet dolorem sit</span>
</svg>
</div>
You need to animate the stroke-dashoffset attribute. At the beginning stroke-dasharay = the path's total length (calculated with .getTotalLength()). Since you are using only one value the dashes and the gaps are of equal length.
stroke-dasharray="137.35"
Also the stroke-dashoffset="137.35". This means that you don't see the dash. In this moment your stroke is the gap.
Next you are animating the stroke-dashoffset. If you want to see 10% of the dash yoi need to animate the stroke-dashoffset from 100% to 90% i.e
100% {
stroke-dashoffset: 123.6;
}
I hope it helps.
.svg-item {
flex: 1;
font-size: 16px;
max-width: 400px;
margin: 0 auto;
}
.data-des {
font-size: 0.7em;
display: block;
font-weight: bold;
text-align: center;
margin-top: 10px;
}
.donut-ring-ext {
stroke: #50b180;
}
.donut-segment {
transform-origin: center;
}
.donut-segment-2 {
stroke: #a8df8a;
animation: donut1 1s forwards;
}
.donut-segment-3 {
stroke: #a8df8a;
animation: donut2 1s;
}
.donut-segment-4 {
stroke: #a8df8a;
animation: donut3 1s;
}
.donut-percent {
color: #3c8560;
animation: donutfadelong 1s;
}
#keyframes donut1 {
100% {
stroke-dashoffset: 123.6;
}
}
.donut-label {
font-size: 0.28em;
font-weight: 700;
line-height: 1;
fill: #000;
transform: translateY(0.25em);
}
.donut-percent {
font-size: 0.5em;
line-height: 1;
transform: translateY(0.5em);
font-weight: 100;
}
.donut-data {
font-size: 0.12em;
line-height: 1;
transform: translateY(0.5em);
text-align: center;
text-anchor: middle;
color: #666;
fill: #666;
animation: donutfadelong 1s;
}
svg{border:1px solid}
<div class="svg-item">
<svg viewBox="-30 -10 100 100" class="donut">
<g transform="rotate(-90 20 20)">
<circle
class="donut-hole"
cx="20"
cy="20"
r="15.91549430918954"
fill="#f00"
></circle>
<circle
class="donut-ring-ext"
cx="20"
cy="20"
r="19"
fill="transparent"
stroke-width="2"
></circle>
<circle
class="donut-segment donut-segment-2"
cx="20"
cy="20"
r="22"
fill="transparent"
stroke-width="2"
stroke-dasharray="137.35"
stroke-dashoffset="137.35"
></circle></g>
<g class="donut-text donut-text-1">
<text y="50%" transform="translate(0, 2)">
<tspan
x="50%"
text-anchor="middle"
class="donut-percent"
>
10%
</tspan>
</text>
</g>
<span class="data-des">Amet dolorem sit</span>
</svg>
</div>

Animate a rotating tooltip without rotating text itself (CSS)

I would like to create a tooltip which consists of a line that rotates around an icon when hovered, as the diagram below shows.
Rotation part is not difficult, but I am having trouble getting the text to stay parallel to the page. Any help, if possible with an example, would be much appreciated.
The closest I have come up with is:
html,
body {
height: 100%;
margin: 0;
}
body {
display: flex;
align-items: center;
background-color: black;
color: white;
}
svg {
width: 256px;
height: 256px;
}
svg > g {
transform: translate(128px, 128px);
}
#ticks > line {
stroke: white;
}
#hands {
stroke: white;
stroke-width: 4px;
transform: rotate(-90deg);
}
#second, .label {
animation: handrotation 40s infinite alternate;
}
.label {
transform-origin: -100px;
position: relative;
left: 50px;
}
#second > line {
stroke: white;
stroke-width: 1px;
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 8s forwards;
}
#keyframes dash {
to {
stroke-dashoffset: 00;
}
}
#keyframes handrotation {
to {
transform: rotate(0.1turn);
}
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<g>
<g id="second">
<line x1="-12" y1="0" x2="120" y2="0"/>
</g>
<span class="label">label</span>
</g>
</g>
</svg>

How to do that animation begins after page is fully loaded?

I have animation (#svg_tag, .st0). After animation complete, then fades-in the image (.logo_svg). I want that animation begins after page is fully loaded (both animation and image).
.logo_svg {
max-width: 80%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
opacity: 0;
animation-name: show;
animation-delay: 11s;
animation-duration: 1s;
animation-fill-mode: forwards;
animation-iteration-count: 1;
animation-timing-function: linear;
}
body{
background-color: grey;
}
#svg_tag {
max-width: 80%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.st0 {
fill-opacity: 0;
stroke: #fff;
stroke-width: 1;
stroke-dasharray: 1350;
stroke-dashoffset: 1350;
animation: draw 15s linear;
animation-delay: 5s;
}
#keyframes draw {
to {
stroke-dashoffset: 0;
}
}
#keyframes show {
to {
opacity: 1;
}
}
<body>
<svg version="1.1" id="svg_tag" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 708.7 437.3" style="enable-background:new 0 0 708.7 437.3;" xml:space="preserve">
<path id="XMLID_13_" class="st0" d="M708.7,285c-18.6,18.6-47.7,21.9-70,7.9v102.3l70,42V285z"/>
<path id="XMLID_12_" class="st0" d="M595.6,113.1l-113.1,67.9v7.5H509V245c0,16.6,13.4,30,30,30s30-13.4,30-30v-56.5h26.5v113.1
h-26.5v-8.6c-9,5.6-19.4,8.6-30,8.6c-31.2,0-56.5-25.3-56.5-56.5v56.5l129.6,77.8V188.5h26.5v8.6c22.3-14,51.4-10.7,70,7.9v-24.1
L595.6,113.1z"/>
<circle id="XMLID_11_" class="st0" cx="669" cy="245" r="30"/>
<path id="XMLID_10_" class="st0" d="M242.7,188.5h-9.9V245c0,25.7-20.9,46.6-46.6,46.6s-46.6-20.9-46.6-46.6v-56.5h-9.9V245
c0,31.2,25.3,56.5,56.5,56.5c18.6,0,36.1-9.2,46.6-24.5v24.5h9.9V188.5z"/>
<polyline id="XMLID_9_" class="st0" points="279.2,188.5 259.3,188.5 259.3,198.4 269.2,198.4 269.2,301.6 279.2,301.6 279.2,188.5
"/>
<path id="XMLID_8_" class="st0" d="M259.3,123c0-5.5,4.4-9.9,9.9-9.9s9.9,4.4,9.9,9.9s-4.4,9.9-9.9,9.9S259.3,128.5,259.3,123
L259.3,123z"/>
<rect id="XMLID_7_" x="295.7" y="113.1" class="st0" width="9.9" height="188.5"/>
<path id="XMLID_16_" class="st0" d="M425.4,0v213c-17.7-25.7-52.9-32.3-78.6-14.6c-25.7,17.7-32.3,52.9-14.6,78.6
c17.7,25.7,52.9,32.3,78.6,14.6c5.7-3.9,10.7-8.9,14.6-14.6v24.5h9.9V0H425.4z M378.8,291.6c-25.7,0-46.6-20.9-46.6-46.6
s20.9-46.6,46.6-46.6s46.6,20.9,46.6,46.6S404.5,291.6,378.8,291.6z"/>
<path id="XMLID_15_" class="st0" d="M103.1,213c-17.7-25.7-52.9-32.3-78.6-14.6c-5.7,3.9-10.7,8.9-14.6,14.6V0H0v301.6h9.9V277
c17.7,25.7,52.9,32.3,78.6,14.6C114.3,273.9,120.8,238.7,103.1,213z M56.5,291.6c-25.7,0-46.6-20.9-46.6-46.6s20.9-46.6,46.6-46.6
s46.6,20.9,46.6,46.6S82.3,291.6,56.5,291.6z"/>
</svg>
<img src="logo.png" class="logo_svg" alt="" />
</body>
Thanks for uploading the HTML.
Correct me if I'm wrong, but I think you want to animate the logo, to draw itself, when the page loads. And then you want to animate another logo, that fades in.
If the logotypes are the same - then you can animate the first SVG logo itself, with one animation. No need for two :)
Here's a little codepen that does exactly that.
Here's the essential animation:
svg{
max-width: 80%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.st0 {
fill-opacity: 0;
stroke: #fff;
stroke-width: 1;
stroke-dasharray: 1350;
stroke-dashoffset: 1350;
animation: draw 5s linear forwards;
}
#keyframes draw {
95% {
stroke-dashoffset: 0;
fill-opacity:0;
stroke-width:1;
}
100%{
fill-opacity:1;
stroke-width:0;
}
}
Does this solve your problem?

Resources