Rotating an SVG element using css :hover only leads to element flickering - css

For the full code have a look at https://codepen.io/fcc-danielw/pen/oNBLjrj
The relevant partials are shown below:
<svg width="235" height="381" viewBox="0 0 235 381" fill="none" xmlns="http://www.w3.org/2000/svg">
...
<g id="images">
<g id="img1">
<rect id="Rectangle 10" x="37" y="158" width="71" height="71" rx="3" fill="#C4C4C4" fill-opacity="0.25" />
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="38" y="159" width="70" height="70">
<rect id="Rectangle 9" x="38" y="159" width="70" height="70" rx="3" fill="#C4C4C4" />
</mask>
<g mask="url(#mask0)">
<g id="mountains">
<path id="Polygon 1" d="M58.5 187L89.2439 229.75H27.7561L58.5 187Z" fill="#C4C4C4" />
<path id="Polygon 2" d="M94.5 187L125.244 229.75H63.7561L94.5 187Z" fill="#C4C4C4" />
</g>
</g>
</g>
...
</g>
...
</svg>
#img1 {
transform: rotate(0deg);
}
#img1:hover {
transform: rotate(45deg);
transform-origin: 50% 50%;
transform-origin: 35px 35px;
}
For some reason, when hovering over #img1, rather than rotating as expected, it simply starts flickering. What is the issue here? What am I doing wrong?

The element not flickering , hover effect just repeated several times.
You can stop this by using transition.
You're #img element CSS should be like this
#img1 {
transform: rotate(0deg);
transition: 9s;
}

Related

Animating feComposite SVG filter elements

I have two svg shapes, one on top of the other, and I've applied the feComposite filter on both so that the top shape knocks out part of the bottom shape. The code is as follows and works fine.
<svg width="100" height="100">
<defs>
<filter id="myfilter">
<feImage xlink:href="#layer1" result="lay1"/>
<feImage xlink:href="#layer2" result="lay2"/>
<feComposite operator="out" in="lay1" in2="lay2"/>
</filter>
</defs>
<g filter="url(#myfilter)">
<circle id="layer1" cx="50" cy="50" r="40" stroke-
width="0" fill="green" />
<circle id="layer2" class="small" cx="20" cy="60" r="20" stroke-
width="0" fill="red" />
</g>
</svg>
Now I want to animate the top shape, but when I tried to apply the animation, both shapes animates and I can't figure out why because I've only targeted the second shape with class="small". Here is the css code for the animation.
#keyframes rock {
0% {
transform: rotate(45deg);
}
50% {
transform: rotate(0deg);
}
100% {
transform: rotate(-45deg);
}
}
.small {
animation-name: rock;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
I am puzzled by this behavior and hope someone can shed some light to this problem. Is it not possible to animate the svg elements individually when filters are applied to them as a group? But that doesn't seem to make sense because the svg elements can be targeted individually.
Here is a link to codepen: https://codepen.io/lanlanonearth/pen/bGbRyVo
Please try this: You put both circles in the <defs> and you <use xlink:href="#layer1". Next you apply the filter to the <use> element.
<svg width="100" height="100">
<defs>
<circle id="layer1" cx="50" cy="50" r="40" stroke-width="0" fill="green" />
<circle id="layer2" class="small" cx="20" cy="60" r="20" stroke-width="0" fill="red" />
<filter id="myfilter">
<feImage xlink:href="#layer1" result="lay1"/>
<feImage xlink:href="#layer2" result="lay2"/>
<feComposite operator="out" in="lay1" in2="lay2"/>
</filter>
</defs>
<use xlink:href="#layer1" filter="url(#myfilter)"></use>
</svg>
Check it on codepen

Why is blue circle not spinning in the center of itself [duplicate]

This question already has an answer here:
CSS transform origin issue on svg sub-element
(1 answer)
Closed 3 years ago.
Why is the blue circle not rotating in the center of its own axis?
Below you can find my previous code.
Here you can see my CSS with the proportionate SVG:
circle {
animation: grow 2s infinite;
transform-origin: center;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(0.5);
}
100% {
transform: scale(1);
}
}
<svg xmlns="http://www.w3.org/2000/svg"
width="80"
height="110"
version="1.1">
<rect width="70"
height="100"
x="5"
y="5"
fill="white"
stroke="red"
stroke-width="10"
rx="5"/>
<circle cx="40" cy="105" r="3" fill="blue"/>
</svg>
You need transform-box: fill-box;
circle {
animation: grow 2s infinite;
transform-origin: center;
transform-box: fill-box;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(0.5);
}
100% {
transform: scale(1);
}
}
<svg
xmlns="http://www.w3.org/2000/svg"
width="80"
height="110"
version="1.1"
>
<rect
width="70"
height="100"
x="5"
y="5"
fill="white"
stroke="red"
stroke-width="10"
rx="5"
/>
<circle cx="40" cy="105" r="3" fill="blue" />
</svg>
Because scale in SVG is different, it makes scale in X & Y axis. Additionally it scales "cx" and "cy" properties.
The best way is to make "cx" & "cy" at 0 and use the "translate" to coordinates you need
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="110" version="1.1">
<rect
width="70"
height="100"
x="5"
y="5"
fill="white"
stroke="red"
stroke-width="10"
rx="5" />
<circle cx="0" cy="0" r="3" fill="blue" transform="translate(40 105)">
<animateTransform
attributeName="transform"
type="scale"
additive="sum"
from="1 1"
to="1 1"
values="1 1; 0.5 0.5; 1 1"
begin="0s"
dur="2s"
repeatCount="indefinite">
</animateTransform>
</circle>
</svg>
Enjoy!

CSS :hover on SVG group area instead of rendered pixels, pointer-events: bounding-box not working cross browser. How to workaround

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,

How to get scale works cross-browser in center position on SVG elements with CSS

I have some SVG elements, which should be scaled on hover (see the attached code snippet below please). It works well on WebKit browsers (adding transform-origin: 50% 50%; to g element did the job). But Firefox seems to scale it in own way (like need to get some extra translate(x,y) and Edge doesn't scale it at all. What are your suggestions? Am I doing it wrong or should use a separate styling for different browser engines? I would like to solve it with CSS however, this is just an example. There are more g elements to be scaled with different x and y positions.
g {
transition: all 0.5s;
cursor: pointer;
transform-origin: 50% 50%;
}
g:hover {
transform: scale(1.5);
}
<svg height="260px" width="1106px" viewBox="0 0 1106 260">
<g><rect fill="#ffffff" height="13" rx="2" ry="2" stroke="#b3b3b3" stroke-width="1" width="30" x="20" y="78.5"></rect><text fill="#999999" font-family="Verdana" font-size="9" x="25" y="88.5">REC</text></g>
<g><rect fill="#ffffff" height="13" rx="2" ry="2" stroke="#b3b3b3" stroke-width="1" width="30" x="32.5" y="128.5"></rect><text fill="#999999" font-family="Verdana" font-size="9" x="37.5" y="138.5">REC</text></g>
</svg>
You've assumed the transform-box is the fill-box, it's not by default it's the view-box. I've adjusted the box model to match your expectations below.
g {
transition: all 0.5s;
cursor: pointer;
transform-origin: 50% 50%;
transform-box: fill-box;
}
g:hover {
transform: scale(1.5);
}
<svg height="260px" width="1106px" viewBox="0 0 1106 260">
<g><rect fill="#ffffff" height="13" rx="2" ry="2" stroke="#b3b3b3" stroke-width="1" width="30" x="20" y="78.5"></rect><text fill="#999999" font-family="Verdana" font-size="9" x="25" y="88.5">REC</text></g>
<g><rect fill="#ffffff" height="13" rx="2" ry="2" stroke="#b3b3b3" stroke-width="1" width="30" x="32.5" y="128.5"></rect><text fill="#999999" font-family="Verdana" font-size="9" x="37.5" y="138.5">REC</text></g>
</svg>
g {
transition: all 0.5s;
cursor: pointer;
transform-origin: 50% 50%;
}
g:hover {
transform: scale(1.5);
}
<svg height="260px" width="1106px" viewBox="0 0 1106 260">
<g><rect fill="#ffffff" height="13" rx="2" ry="2" stroke="#b3b3b3" stroke-width="1" width="30" x="20" y="78.5"></rect><text fill="#999999" font-family="Verdana" font-size="9" x="25" y="88.5">REC</text></g>
<g><rect fill="#ffffff" height="13" rx="2" ry="2" stroke="#b3b3b3" stroke-width="1" width="30" x="32.5" y="128.5"></rect><text fill="#999999" font-family="Verdana" font-size="9" x="37.5" y="138.5">REC</text></g>
</svg>

Animating an SVG Group

I currently have the following SVG:
<svg class="tower owner" height="60" width="60" viewBox="0 0 300 300">
<g transform="translate(75 75)" opacity="1">
<ellipse class="border" cx="0" cy="0" fill="#222" rx="65" ry="65" stroke-width="5"></ellipse>
<g class="rotatable" style="transform: rotate(5.497787143782138rad); transition: transform 2s;">
<rect fill="#aaa" height="50" stroke-width="7" stroke="#181818" width="40" x="-20" y="-80"></rect>
<rect fill="#555" height="58" rx="12" ry="10" width="78" x="-39" y="-25"></rect>
<rect fill="#ffe56d" height="46.4" y="-13.399999999999999" rx="12" ry="12" width="78" x="-39"></rect>
</g>
</g>
</svg>
I am currently animating a rotation on g.rotatable however I would like to use <animateTransform> if possible, and I haven't figured out how.
I have tried placing it at the start of the group, at the bottom of it, and even after it, however none have any affect.
<animateTransform attributeName="transform" attributeType="XML" dur="5s" keyTimes="0;0.4;0.75;1" repeatCount="indefinite" type="rotate" values="315deg;90deg;200deg;315deg" calcMode="linear"></animateTransform>
Since I've never really worked with SVGs or animating them, I'm not sure where I'm going wrong.
svg.tower .rotatable {
animation: tower 5s linear infinite;
}
#keyframes tower {
0% {
transform: rotate(315deg);
}
40% {
transform: rotate(90deg);
}
75% {
transform: rotate(200deg);
}
100% {
transform: rotate(315deg);
}
}
Above is my current CSS animation.
Can anyone tell me where I'm going wrong, so I can fix my mistakes, or if it's even possible, so I can potentially give up this line of action.
Note: You may want to reconsider using SMIL animations instead of CSS animations because Chrome has deprecated support for SMIL animations from v45.
There were two problems in your code and they are as follows:
The rotate transform in SVG just takes the degree number as value and doesn't need the deg suffix to be added to it. In addition a transform origin can also be specified (2nd and 3rd param) but it is not mandatory.
There was a style='transform: rotate(...)' on the .rotatable element. The CSS overrides the animateTransform and so you don't get to see any rotation. Avoid this stylesetting. If there is a need for an initial rotation you could probably use SVG's transform attribute.
Below is a working demo:
<svg class="tower owner" height="60" width="60" viewBox="0 0 300 300">
<g transform="translate(75 75)" opacity="1">
<ellipse class="border" cx="0" cy="0" fill="#222" rx="65" ry="65" stroke-width="5"></ellipse>
<g class="rotatable" transform="rotate(315)">
<rect fill="#aaa" height="50" stroke-width="7" stroke="#181818" width="40" x="-20" y="-80"></rect>
<rect fill="#555" height="58" rx="12" ry="10" width="78" x="-39" y="-25"></rect>
<rect fill="#ffe56d" height="46.4" y="-13.399999999999999" rx="12" ry="12" width="78" x="-39"></rect>
<animateTransform attributeName="transform" attributeType="XML" dur="5s" keyTimes="0;0.4;0.75;1" repeatCount="indefinite" type="rotate" values="315;90;200;315" calcMode="linear"></animateTransform>
</g>
</g>
</svg>

Resources