I'm working on some animated SVGs with CSS animations that triggers on hover.
I'm being able to have the SVG animate on hover the way I want to for Chrome but I'm facing a Firefox and Safari issue.
Apparently, the pointer-events property applied to groups <g></g> doesn't give same behavior on this browser than on the other modern ones, at least when trying to set the value to bounding-box.
I'm doing
g {
pointer-events: bounding-box;
}
but the hover only gets triggered when the actual <path> element is hovered, not the whole group <g> as I would need to.
Can I use doesn't say anything about this, it mentions svgs also have support for this property.
Below there's a sample code for you to see how one of my SVGs looks like.
On chrome hovering the main containing group area will trigger the hover animation, on Firefox the actual path (the icon lines in this case) needs to be hovered in order to that to happen.
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<style>
g {
pointer-events: bounding-box;
//not working on FF
}
#mobile:hover .flip {
transform-origin:55% 50%;
-moz-transform-origin:55% 50%;
animation: flip_left 1.6s forwards;
}
#keyframes flip_left {
0% {transform: perspective(2000px) rotateY(90deg) skewY(-1deg)}
30% {transform:perspective(2000px) rotateY(-25deg) skewY(-0.8deg)}
50% {transform:perspective(2000px) rotateY(20deg) skewY(0.8deg)}
70% {transform:perspective(2000px) rotateY(-10deg) skewY(-0.8deg)}
100% {transform:perspective(2000px) rotateY(0deg)}
}
</style>
<!-- Generator: Sketch 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
<title>Mobile solutions</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="mobile" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="MS_HP_Usecase_Based_Page-Desktop-2A" transform="translate(-766.000000, -418.000000)" stroke="#00A0DF" stroke-width="1.25">
<g id="Asset-5" transform="translate(766.000000, 418.000000)">
<g class="flip">
<rect id="Rectangle-path" stroke-linecap="round" stroke-linejoin="round" x="12.35" y="7.41" width="15.32" height="25.33" rx="2.03"></rect>
<circle id="Oval" stroke-linecap="round" stroke-linejoin="round" cx="20.01" cy="28.72" r="1.58"></circle>
<path d="M18.43,10.72 L21.48,10.72" id="Shape" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
<circle id="Oval" cx="19.67" cy="19.67" r="19.04"></circle>
</g>
</g>
</g>
</svg>
I would like to find a workaround for this, since I want to make this animations work cross browser. I would like to eventually make it work for IE11 and Edge too.
Thanks,
So pointer-events: bounding-box seems to not be supported by most browsers.
I implemented the workaround #ccprog suggested on the comments section of my question.
I added a <rect fill="none"> element to svg, that is same dimensions than the SVG itself. I added a :hover selector for that element and sibling selector ~ to select its sibling group with the flip class inside.
See CSS:
#mobile-hover {
visibility: visible;
pointer-events: visible;
}
#mobile-hover:hover ~ .group .flip {
-moz-transform-origin:55% 50%;
-webkit-transform-origin: 55% 50%;
transform-origin:55% 50%;
-webkit-animation: flip_left 1.6s forwards;
animation: flip_left 1.6s forwards;
}
I found out I had to add pointer-events: visible to the rect element so it would detect the :hover. I added visibility: visible as a requirement to pointer-events: visible to work.
Below the full new SVG code:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mobile-icon">
<style>
#mobile-hover {
visibility: visible;
pointer-events: visible;
}
#mobile-hover:hover ~ .group .flip {
-moz-transform-origin:55% 50%;
-webkit-transform-origin: 55% 50%;
transform-origin:55% 50%;
-webkit-animation: flip_left 1.6s forwards;
animation: flip_left 1.6s forwards;
}
#keyframes flip_left {
0% {transform: perspective(2000px) rotateY(90deg) skewY(-1deg)}
30% {transform:perspective(2000px) rotateY(-25deg) skewY(-0.8deg)}
50% {transform:perspective(2000px) rotateY(20deg) skewY(0.8deg)}
70% {transform:perspective(2000px) rotateY(-10deg) skewY(-0.8deg)}
100% {transform:perspective(2000px) rotateY(0deg)}
}
</style>
<!-- Generator: Sketch 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
<title>Mobile solutions</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="mobile" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" >
<rect fill="none" width="40" height="40" id="mobile-hover">
</rect>
<g id="MS_HP_Usecase_Based_Page-Desktop-2A" transform="translate(-766.000000, -418.000000)" stroke="#00A0DF" stroke-width="1.25" class="group">
<g id="Asset-5" transform="translate(766.000000, 418.000000)">
<g class="flip">
<rect id="Rectangle-path" stroke-linecap="round" stroke-linejoin="round" x="12.35" y="7.41" width="15.32" height="25.33" rx="2.03"></rect>
<circle id="Oval" stroke-linecap="round" stroke-linejoin="round" cx="20.01" cy="28.72" r="1.58"></circle>
<path d="M18.43,10.72 L21.48,10.72" id="Shape" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
<circle id="Oval" cx="19.67" cy="19.67" r="19.04"></circle>
</g>
</g>
</g>
</svg>
Works on Chrome, Safari and Firefox and I'm attempting to test IE11 and Edge next.
Many thanks,
I have a simple SVG that animates when it comes into viewport (via added class in Javascript). It's a simple bar chart that is supposed to animate the height of 2 rect elements.
It works fine everywhere except iPad Safari 11.1.2 (and maybe below)
When I remove the animation the SVG displays fine. The class is being added via javascript and webkit vendor prefixes are added for browser support.
<style type="text/css">
#keyframes draw {
from {
height: 0;
}
to {
height: 110px;
}
}
#keyframes drawBig {
from {
height: 0;
}
to {
height: 360px;
}
}
#-webkit-keyframes draw {
from {
height: 0;
}
to {
height: 110px;
}
}
#-webkit-keyframes drawBig {
from {
height: 0;
}
to {
height: 360px;
}
}
.animate-bar {
animation: draw 1s linear forwards;
animation-play-state: paused;
-webkit-animation: draw 1s linear forwards;
-webkit-animation-play-state: paused;
}
.animate-bar.bar-large {
animation-name: drawBig;
-webkit-animation-name: drawBig;
}
.play .animate-bar {
animation-play-state: running;
-webkit-animation-play-state: running;
}
</style>
<svg id="diagram" viewBox="0 0 290 472" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="svg" stroke="none" stroke-width="1" fill="#000000" fill-rule="evenodd">
<g id="left">
<rect class="animate-bar" x="0" y="283" width="132" height="107" rx="3" transform="scale(1,-1) translate(0,-676)">
</rect>
<text font-weight="bold">
<tspan x="47.384" y="263">1129</tspan>
</text>
</g>
<g id="right" transform="translate(152,0)">
<rect class="animate-bar bar-large" fill="#EEE6E2" x="0" y="33" width="132" height="360" rx="3" transform="scale(1,-1) translate(0,-426)">
</rect>
<text font-weight="bold">
<tspan x="36.56" y="17">4000</tspan>
</text>
</g>
</g>
</svg>
The CSS is just manipulating the height of the bars in the animation (which is paused until the class is added).
On iOS 11 though the bars just never animate so both heights appear to be 0 and you can't see either.
When I look in dev tools I can see the <rect> elements flashing in the DOM indicating something is happening to them (even though the only thing that should manipulate them is the CSS animation) but they are flashing very fast so I can't see what.
I'm at a loss of what else to try.
Here is a fiddle of the code:
http://jsfiddle.net/peuzdL2n/7/
Works in everything except iOS Safari 11 and below as far as I can see
Assuming I have an svg made with inkscape.
In this SVG set with a viewbox, I want to animate each element inside the SVG.
There is no problem for translate or opacity ... but when I need to rotate or scale a single element, it acting weird.
I try to correctly understand the concept of the viewbox but I need some help.
I understand that I have only one origin point when I have only one viewbox should I set multiple viewbox ?
<?xml version="1.0" encoding="UTF-8"?>
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
// rotate or scale acting weird
<ellipse id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
// rotate or scale acting weird
<rect id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00;paint-order:normal"/>
// rotate or scale acting weird
<path id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;paint-order:normal"/>
</svg>
I'm using anime.js 3.0 or CSS or I can try anything else
In Svg, the coordinates of any figure always have an absolute value that is calculated from the upper left corner of the SVG canvas.
Therefore, when applying the scale (2) command, the coordinates of the center of the figure will also be doubled and the figure will shift to the right and down.
<svg id="SVGRoot" version="1.1" width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" style="border:1px solid grey;">
<rect id="rect9240" transform="scale(2)" x="100" y="100" width="100" height="100" style="fill-rule:evenodd;fill:#f00;> stroke:#000; paint-order:normal">
<animateTransform
xlink:href="#rect9240"
attributeName="transform"
type="scale"
values="1;2;2;1;1"
dur="8s"
fill="freeze"
repeatcount="indefinite"
/>
</rect>
<circle cx="150" cy="150" r="3" fill="black" />
<circle cx="300" cy="300" r="3" fill="dodgerblue" />
<text x="150" y="140" font-size="16px" text-anchor="middle" > Center (150,150) </text>
<text x="300" y="290" font-size="16px" text-anchor="middle" > Center (300,300) </text>
</svg>
To return the enlarged figure to its original position, you must use the command translate (X, Y)
There is a great post here by #Paul LeBeau where this is explained in detail.
CSS solution
In order not to calculate the position of the center of the figure, you can use the CSS rule transform-box: fill-box
When the value of the fill-box attribute is selected
The object bounding box is used as the reference box.
Below is an example of increasing and decreasing the size of figures:
svg {
width:50%;
}
.ellipse1, .rect1, .path1 {
transform-box: fill-box;
animation: scale 3s linear infinite alternate;
animation-direction: alternate;
transform-origin:50% 50%;
}
#keyframes scale {
0% { transform: scale(0.5); }
100% { transform: scale(1); }
}
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
<ellipse class="ellipse1" id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
<rect class="rect1" id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00; stroke:#000; paint-order:normal"/>
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
Rotation example
svg {
width:50%;
}
.ellipse1, .rect1, .path1 {
transform-box: fill-box;
animation: spin 4s linear infinite alternate;
transform-origin:50% 50%;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
<ellipse class="ellipse1" id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
<rect class="rect1" id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00; stroke:#000; paint-order:normal"/>
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
Increase and rotation
svg {
width:50%;
}
.ellipse1, .rect1, .path1 {
transform-box: fill-box;
animation: scale1 4s linear, spin 4s linear 4s infinite alternate;
transform-origin:50% 50%;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#keyframes scale1 {
0% { transform: scale(0.5);}
100% { transform: scale(1);}
}
<svg id="SVGRoot" version="1.1" viewBox="0 0 700 500" xmlns="http://www.w3.org/2000/svg">
<ellipse class="ellipse1" id="path9238" cx="332.91" cy="143.85" rx="64.941" ry="67.676" style="fill-rule:evenodd;fill:#f00;stroke:#000"/>
<rect class="rect1" id="rect9240" x="400.59" y="270.31" width="173.63" height="177.73" style="fill-rule:evenodd;fill:#f00; stroke:#000; paint-order:normal"/>
<path class="path1" id="path9242" d="m233.79 453.52-153.64-138.25 196.55-63.937z" style="fill-rule:evenodd;fill:#f00;stroke:#000; paint-order:normal"/>
</svg>
I guess you mean the transform-origin CSS propierty. It is related to the center point of the svg file. Then, you need to calculate the center point of the element to animate related to document's center point.
For the animations you can use CSS animations.
The basics of viewBox is that the 4 numbers are "x y width height”. Generally the x/y coordinates are 0 which keeps your origin in the top left corner. Something people often do is place the origin in the middle.
In order to do that you move your viewBox top left by half of the width and half the height. In your case "-350 -250 700 500".
First of all, it is working 100% fine for me on Chrome, but works just as title described when on Firefox
I'm trying to make a simple animation (using transitions) to run indefinitely when mouseover and to slowly go back to initial position when mouseout
The problem is that it is not behaving the same way in Firefox
As requested, here's a minimized and simplified code that reproduces my current issue:
var arcs = $("#logoSec");
var greenarc = $(".greenarc");
var garcMs = 2100; // In ms
var arcsAnimBool = false; // If false, stops the anim loop
greenarc.css({
transition: "transform " + (garcMs * 1) + "ms ease-in-out"
});
function greenArcNormal() {
if (!arcsAnimBool) return;
greenarc.css("transform", "rotate(70deg)");
setTimeout(greenArcRevert, garcMs); // Call the reverse rotation after garcMs ms
}
function greenArcRevert() {
if (!arcsAnimBool) return;
greenarc.css("transform", "rotate(-70deg)");
setTimeout(greenArcNormal, garcMs); // Call the normal rotation after garcMs ms
}
arcs.hover(
function() { // On mouseover
arcsAnimBool = true;
greenarc.css({
transition: "transform " + (garcMs * 1) + "ms ease-in-out"
});
greenArcNormal();
},
function() { // On mouseout
arcsAnimBool = false; // Set to false to stop the infinite loop of greenArcRevert/Normal
greenarc.css("transform", "rotate(0deg)"); // Revert arc back to initial position
greenarc.css({
transition: "transform " + (garcMs * 0.5) + "ms ease-in-out"
});
}
);
#ArcsLogo {
height: 550px;
}
#logoSec {
display: flex;
background-color: #fdfdfd;
}
<div id="logoSec">
<svg class="arcs" version="1.1" id="ArcsLogo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-12 30 383.4 407.5" style="enable-background:new 0 0 383.4 407.5;" xml:space="preserve">
<style type="text/css">
.greenarc {
fill: #00ff00;
transform-origin: 50% 50%;
}
.graycircle {
fill: #5d5d5d;
transform-origin: 50% 50%;
}
.redarc {
fill: #ff0000;
transform-origin: 50% 50%;
}
</style>
<path id="GreenArc" class="greenarc" d="M201.1,62.7c-3.2,0-6.3,0.1-9.4,0.3c77.7,5.5,136.2,72.9,130.7,150.6
c-4.9,70-60.7,125.8-130.7,130.7c3.1,0.2,6.3,0.4,9.4,0.4c77.9,0,141-63.1,141-141S279,62.7,201.1,62.7L201.1,62.7z" />
<circle id="GrayCircle" class="graycircle" cx="191.7" cy="203.7" r="21.2" />
<path id="RedArc" class="redarc" d="M60.2,203.7c0-84.6,65.9-154.6,150.4-159.6c-3.1-0.2-6.3-0.3-9.5-0.3
C112.8,43.2,40.7,114.2,40,202.5c-0.7,88.3,70.3,160.4,158.6,161.1c0.8,0,1.7,0,2.5,0c3.2,0,6.3-0.1,9.5-0.3
C126.2,358.3,60.2,288.3,60.2,203.7z" />
</svg>
</div>
(Simplified code in jsfiddle)
https://jsfiddle.net/Ferdam/htxcwanu/28/
(Old full code: https://jsfiddle.net/Ferdam/9kz52e6h/3/)
I have little experience with HTML/JS/JQuery/CSS so I might be missing something basic, I don't know.
Any help is appreciated. Thanks!
Edit:
Quoting directly what I answered to nivoli:
I forgot to mention that I tried using keyframes before, but the
problem is that I couldn't get it to work like the code I provided
because whenever I hoverout the elements just 'teleport' back to
initial position, which is why I started using css transitions.
I just couldn't find a way to animate the elements back to initial position
using keyframes
No javascript necessary; just use css animations. I only did the green one for you:
#ArcsLogo {
height: 550px;
}
#logoSec {
background-color: #fefefe;
}
.greenarc {
fill: #00ff00;
transform-origin: 50% 50%;
transform: rotate(70deg);
animation: myRotate 4200ms alternate infinite ease-in-out;
}
.graycircle {
fill: #5d5d5d;
transform-origin: 50% 50%;
}
.redarc {
fill: #ff0000;
transform-origin: 50% 50%;
}
#keyframes myRotate {
0% {
transform: rotate(70deg);
}
100% {
transform: rotate(-70deg);
}
}
<div id="logoSec">
<svg class="arcs" version="1.1" id="ArcsLogo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-12 30 383.4 407.5" style="enable-background:new 0 0 383.4 407.5;" xml:space="preserve">
<path id="GreenArc" class="greenarc" d="M201.1,62.7c-3.2,0-6.3,0.1-9.4,0.3c77.7,5.5,136.2,72.9,130.7,150.6
c-4.9,70-60.7,125.8-130.7,130.7c3.1,0.2,6.3,0.4,9.4,0.4c77.9,0,141-63.1,141-141S279,62.7,201.1,62.7L201.1,62.7z" />
<circle id="GrayCircle" class="graycircle" cx="191.7" cy="203.7" r="21.2" />
<path id="RedArc" class="redarc" d="M60.2,203.7c0-84.6,65.9-154.6,150.4-159.6c-3.1-0.2-6.3-0.3-9.5-0.3
C112.8,43.2,40.7,114.2,40,202.5c-0.7,88.3,70.3,160.4,158.6,161.1c0.8,0,1.7,0,2.5,0c3.2,0,6.3-0.1,9.5-0.3
C126.2,358.3,60.2,288.3,60.2,203.7z" />
</svg>
</div>
They key is to define the keyframes, which I just copied from the transform declarations you were making in javascript. Then by adding the animation rule to the greenarc class, we tell it to
use the keyframes myRotate (change the name to whatever you want)
take 4200ms to move from 0% to 100%. I doubled it because I think your logic took 2100ms to move from rotate(0) to rotate(70).
alternate the direction of the animation so that it goes back-and-forth rather than moving in one direction, then snapping back to where it started.
repeat the animation infinitely
use ease-in-out as you were doing in javascript to slow down as it gets closer to the ends.
See the animation documentation for more details and examples.
I'd like to animate an svg's path. I know this can be achieved with <animate>, but the animation starts only after the element is appended to some div. So I need to find another solution, but I weren't able to find any help online.
Here is the fiddle so you can take a look at what I have.
Note: Now I'd like the svg's path to stretch the svg. So at first, it is a triangle, but it needs to smoothly convert into a square that fits the svg around it.
Thank you!
// -- click the path -- //
$('path').on('click touch', function() {
$(this).parents('svg').css({
height: '100vh',
width: '100vw'
});
})
/* -- click the path -- */
* {
margin: 0;
padding: 0;
}
body {
overflow: hidden; /* -- just for this example */
}
svg {
-webkit-transition:
height 350ms ease-in-out,
width 350ms ease-in-out;
transition:
height 350ms ease-in-out,
width 350ms ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- click the path -->
<svg fill="#000" xmlns="http://www.w3.org/2000/svg" version="1.0" height="200" width="200" viewBox="0 0 1024 1024">
<path d="M0 0 L405 0 L405 635"/>
</svg>
SMIL animations (ie. ones using <animate>) can be made to start on a click.
<svg fill="#000" xmlns="http://www.w3.org/2000/svg" version="1.0" height="200" width="200" viewBox="0 0 1024 1024">
<path d="M0 0 L405 0 L405 635 L405 635">
<animate attributeName="d" dur="350ms" to="M0 0 L405 0 L405 635 L0 635"
begin="click" fill="freeze" />
</path>
</svg>