Override SVG transform attributes with CSS - css

I have a SVG element that looks like this:
<image
xmlns="http://www.w3.org/2000/svg"
overflow="visible"
width="54"
height="54"
id="Content-Author-Off_xA0_Image"
xlink:href="data:image/png;base64,..."
transform="matrix(1 0 0 1 0 108)">
</image>
Is it possible to override transform attribute with CSS? I've tried this and it doesn't work:
image {
transform: none;
}

Looks like transform: none doesn't quite work in all browsers (see bugreport) (fixed jan 2017), but it's possible to work around that by using an identity matrix, e.g transform: scale(1). The stylerules will override the attributes, as demonstrated by the following snippet:
circle {
transform-origin: 50%;
transform: scale(1);
transition: transform 0.5s;
}
circle:hover {
transform: scale(2);
}
<svg>
<circle cx="50" cy="50" r="25" transform="translate(500 500)"/>
</svg>
Same as fiddle.

CSS cannot affect an attribute only a CSS property. You could try using a CSS transform instead of an SVG attribute transform in the first place, although not all UAs support CSS transforms on SVG elements yet.
Here's an example of a CSS transform with a rect element. Put the mouse over it to see it change.
rect {
transform: translate(50px, 0) rotate(30deg);
}
rect:hover {
transform: none;
}
<svg>
<rect x="30" y="30" width="50" height="50" fill="red"/>
</svg>

Related

Transform-origin for an SVG group in Electron is ignored

I have a simple SVG icon which I animate in CSS. Here is the SVG:
<svg width="100" height="100" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" className={this.state.isTimewatchActive ? "active" : ""}>
<rect fill="lightgrey" id="background" ry="20" rx="20" height="512" width="512" y="0" x="0" />
<g id="icon">
<path
d="m352.35001,180.85625l-1.2375,-1.16875l12.65,0l5.84375,5.3625l15.46875,-15.675l-28.05,-27.70625l-15.95,15.33125l6.05,6.325l0,12.7875l-3.4375,-3.23125c-21.51875,-19.45625 -48.125,-31.075 -77.6875,-33.61875l0,-26.2625l-22,0l0,26.125l-1.375,0c-30.04375,2.0625 -58.4375,15.46875 -79.75,36.4375l0,-12.2375l6.11875,-6.325l-15.74375,-15.2625l-28.05,27.6375l15.46875,15.675l5.84375,-5.3625l12.2375,0c-0.20625,0 -0.48125,0.48125 -0.6875,0.75625c-22.55,24.13125 -35.0625,55.61875 -35.0625,88.34375c0,71.775 59.19375,130.2125 132.06875,130.2125c72.7375,0 131.93125,-58.36875 131.93125,-130.14375c0,-32.725 -12.375,-64.00625 -34.65,-88zm-91.85,117.90625l-5.5,12.2375l-5.5,-12.2375c-9.625,-2.40625 -16.5,-10.8625 -16.5,-20.96875c0,-9.4875 7.90625,-17.875 16.5,-20.83125l0,-88.9625l11,0l0,88.89375c9.28125,2.54375 16.5,10.93125 16.5,20.9c0,10.10625 -6.875,18.5625 -16.5,20.96875z"
fill="#FFFFFF"
stroke="null"
/>
</g>
</svg>
(I am working in the context of React, so the className attribute is really a class and the expression is evaluated to output the class string.)
This SVG has two states, active (with class="active" on the svg tag) and inactive (the code block above).
Here is the (post)CSS for the two states:
svg {
#icon {
transform: scale(0.8);
transform-origin: center center;
transition: all 0.2s;
}
#shadow {
opacity: 0;
transition: all 0.2s;
}
#background {
transition: all 0.2s;
}
&.active {
#background {
fill: $greenHn;
}
#icon {
transform: scale(1);
}
#shadow {
opacity: 0.2;
}
}
}
So at first, the icon should display at scale 0.8 in the center of the background. In Electron, it is scaled down but the transform origin is top left. The weird thing is that if I open the dev tools in Electron and toggle the transform-origin: center center rule (with the checkbox in the right-hand side panel), and toggle it back on, the rule is correctly applied.
So it doesn't seem to be a CSS problem but then I don't know what to do.
Does anyone have any idea?
Thanks :)
EDIT
As I read that SVG isn't supposed to support transform-origin, I tried using a transform: translate() instead, but I have the same behaviour.

SVG: Can I put x and y position in attributes in the style?

I would like to include positioning x="50%" y="50%" in a class style. Doing this does not work:
.centre {
x: 50%;
y: 50%;
}
Is there any way to include positioning in a style?
Edit:
Based on the answers, translate() should do the job, and indeed the following snippet shows it working. That is, if you’re not using Safari.
Safari doesn’t seem to like doing this on at text element … ?
text.centre {
font-family: sans-serif;
font-size: .5em;
fill: green;
alignment-baseline: middle;
text-anchor:middle;
-webkit-transform: translate(50%,50%);
transform: translate(50%,50%);
}
<svg x="160" y="100" width="140" height="40">
<rect style="fill: lightgrey;" x="0" y="0" width="140" height="100"/>
<rect style="fill: white;" y="10" x="10" width="120" height="20"/>
<svg x="10" y="10" width="120" height="20">
<text class="centre">Hello</text>
</svg>
</svg>
Apparently, yes, you can. If you use the transform css property. See the attached snippet.
svg {
border: 1px solid;
}
rect {
fill: red;
transform: translate(50%, 50%);
}
<svg height="200" width="200">
<rect height="100" width="100"></rect>
</svg>
You can use transform: translate(50%, 50%) the first is the x the second is y. If you need to move only along one axis or another you can use translateX(x) or translateY(y)
You can read more here
you can manipulate the positioning of paths with transform:translate();
so try manipulating your desired path with
.centre{
transform:translate(50%, 50%);
}
maybe you will want to use some vendor prefixes for cross-browser
.centre{
-webkit-transform:translate(50%, 50%);
-ms-transform:translate(50%, 50%);
transform:translate(50%, 50%);
}
i used this to animate logo parts here: http://fire.netzgestaltung.at
specific SVG CSS Properties: https://www.w3.org/TR/SVG/styling.html
more tutorials (ment for animating but uses css):
https://www.smashingmagazine.com/2014/11/styling-and-animating-svgs-with-css/
https://css-tricks.com/animating-svg-css/
https://www.elegantthemes.com/blog/resources/how-to-create-an-animated-logo-with-svg-and-css

Can I fix cross-browser CSS issues with <use xlink>-based SVG sprite without resorting to full inline code?

SUMMARY: Some SVG-targeting CSS effects don't work in Chrome & IE (Firefox is fine) on a <use xlink> SVG sprite but the same CSS works absolutely fine when the same SVG code is truly inline.
JSFIDDLE: http://jsfiddle.net/x8vg8k4p/5/
I am currently using <svg><use xlink:href="#symbol-id" /></svg> blocks to call SVG code from an SVG sprite (as an external file) imported via PHP dynamically.
Some CSS effects are applied to the SVG, both as standard and on hover. All these effects work absolutely fine on Firefox, but on both IE and Chrome, they don't:
The fill attribute on the circle does not take effect
The opacity settings on two internal parts of the SVG (the cross by default and the thumb on hover) do not take effect
I believe there is nothing wrong with the CSS as the same code works absolutely fine if the SVG code is inline and not imported via sprite id reference, which the fiddle demonstrates very clearly.
I've struggled for hours, moving bits of code around, adding and removing extra attributes, and not been able to solve this.
What follows are the relevant excerpts of the full code which can be seen on the JSfiddle link - it seems detrimental to readability to include all code here in the question, but I'm happy to edit the question if someone tells me this is bad form.
not working:
<a><svg><use xlink:href="#thumbs-up" /></svg></a>
working:
<a><svg><!-- truly inline SVG code here --></svg></a>
these parts of the CSS are the bits that fail on Chrome and IE:
a svg circle {fill: #4291c2;}
a svg path#cross {opacity: 0;}
a:hover svg circle {fill: #91c142;}
a:hover svg path#cross {opacity: 1;}
a:hover svg g#hand {opacity: 0;}
finally the SVG code itself:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol id="thumbs-up" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="50"/>
<g id="hand">
<polygon fill="#FFFFFF" points="64.287,37.926 64.287,71.491 80.925,71.491 73.044,37.926 "/>
<path fill="#FFFFFF" d="M54.425,41.857c0-2.634-2.811-4.295-5.025-5.155c-2.728-1.059-4.069-4.203-1.565-8.379
c2.146-3.58-2.084-8.795-6.628-6.058c-5.205,3.134-4.073,11.161-2.468,15.889c0.61,1.798-0.435,1.743-1.756,1.743
c-1.081,0-5.646,0-5.646,0h-8.469c-0.998,0-3.288,6.399-2.289,6.399h10.729c-0.188,0.5-0.406,1.391-0.619,2.544H19.768
c-1.152,0-1.919,7.2-0.714,7.2h10.859c-0.035,0.842-0.049,1.695-0.038,2.544H19.372c-1.195,0-0.277,6.256,0.803,6.256h10.413
c0.245,0.95,0.561,1.813,0.962,2.544H21.331c-1.294,0,1.405,5.811,3.027,5.811h6.978c4.925,0,13.934,0,17.805,0
c3.872,0,5.378-5.477,11.86-5.477V43.891C61.001,43.891,54.425,44.12,54.425,41.857z"/>
</g>
<path id="cross" fill="#FFFFFF" d="M50.042,54.392L39.967,66.389c-0.659,0.854-1.478,1.281-2.454,1.281
c-0.879,0-1.612-0.306-2.198-0.915c-0.586-0.61-0.879-1.355-0.879-2.234c0-0.781,0.195-1.404,0.586-1.867l11.065-13.199
L35.864,37.311c-0.464-0.536-0.696-1.147-0.696-1.831c0-0.806,0.286-1.531,0.859-2.179c0.572-0.646,1.31-0.971,2.211-0.971
c1.023,0,1.852,0.382,2.485,1.145l9.285,11.188l9.547-11.273c0.586-0.706,1.318-1.06,2.198-1.06c0.781,0,1.49,0.275,2.125,0.824
c0.635,0.55,0.953,1.251,0.953,2.105c0,0.83-0.135,1.404-0.403,1.722L54.021,49.495l10.921,13.158
c0.415,0.463,0.623,1.041,0.623,1.729c0,0.937-0.312,1.718-0.935,2.345c-0.622,0.629-1.337,0.942-2.142,0.942
c-0.952,0-1.782-0.427-2.49-1.282L50.042,54.392z"/>
</symbol>
</svg>
I think the best you can do is to use css custom properties:
:root {
--circle-fill: #4291c2;
--hand-fill: #ffffff;
--cross-fill: #ffffff;
--cross-opacity: 0;
--hand-opacity: 1;
}
a {
text-decoration: none;
display: inline-block;
border: none;
cursor: pointer;
position: relative;
width: 25px;
height: 25px;
margin: 0 2px 0 5px;
}
a, a * {
transition: 0.2s all ease-in-out;
}
a svg {
position: absolute;
left:0;
top:0;
width:100%;
height:100%;
}
a:hover {
opacity: 1.0;
transform: rotate(-5deg) scale(1.5);
}
a:hover .thumb {
--circle-fill: #91c142;
--hand-opacity: 0;
--cross-opacity: 1;
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol id="thumbs-up" viewBox="0 0 100 100">
<circle cx="50" cy="49.999" r="50" style="fill: var(--circle-fill)"/>
<g id="hand">
<polygon style="fill: var(--hand-fill); fill-opacity: var(--hand-opacity)" points="64.287,37.926 64.287,71.491 80.925,71.491 73.044,37.926"/>
<path style="fill: var(--hand-fill); fill-opacity: var(--hand-opacity)" d="M54.425,41.857c0-2.634-2.811-4.295-5.025-5.155c-2.728-1.059-4.069-4.203-1.565-8.379
c2.146-3.58-2.084-8.795-6.628-6.058c-5.205,3.134-4.073,11.161-2.468,15.889c0.61,1.798-0.435,1.743-1.756,1.743
c-1.081,0-5.646,0-5.646,0h-8.469c-0.998,0-3.288,6.399-2.289,6.399h10.729c-0.188,0.5-0.406,1.391-0.619,2.544H19.768
c-1.152,0-1.919,7.2-0.714,7.2h10.859c-0.035,0.842-0.049,1.695-0.038,2.544H19.372c-1.195,0-0.277,6.256,0.803,6.256h10.413
c0.245,0.95,0.561,1.813,0.962,2.544H21.331c-1.294,0,1.405,5.811,3.027,5.811h6.978c4.925,0,13.934,0,17.805,0
c3.872,0,5.378-5.477,11.86-5.477V43.891C61.001,43.891,54.425,44.12,54.425,41.857z"/>
</g>
<path id="cross" style="fill: var(--cross-fill); fill-opacity: var(--cross-opacity)" d="M50.042,54.392L39.967,66.389c-0.659,0.854-1.478,1.281-2.454,1.281
c-0.879,0-1.612-0.306-2.198-0.915c-0.586-0.61-0.879-1.355-0.879-2.234c0-0.781,0.195-1.404,0.586-1.867l11.065-13.199
L35.864,37.311c-0.464-0.536-0.696-1.147-0.696-1.831c0-0.806,0.286-1.531,0.859-2.179c0.572-0.646,1.31-0.971,2.211-0.971
c1.023,0,1.852,0.382,2.485,1.145l9.285,11.188l9.547-11.273c0.586-0.706,1.318-1.06,2.198-1.06c0.781,0,1.49,0.275,2.125,0.824
c0.635,0.55,0.953,1.251,0.953,2.105c0,0.83-0.135,1.404-0.403,1.722L54.021,49.495l10.921,13.158
c0.415,0.463,0.623,1.041,0.623,1.729c0,0.937-0.312,1.718-0.935,2.345c-0.622,0.629-1.337,0.942-2.142,0.942
c-0.952,0-1.782-0.427-2.49-1.282L50.042,54.392z"/>
</symbol>
</svg>
<a><svg><use class="thumb" xlink:href="#thumbs-up"/></svg></a>
You can not address an element that is referenced via use. Here is a detailed answer to your question.
Also, refer to this answer, which talks about a possible workaround.
you have to remove "fill" attribute from your svg icons.
Also my advice is using this one https://github.com/Keyamoon/svgxuse for cross-browser solution

Animate image independent of mask?

I'm trying to find a way to animate an image which has a masked applied to it without affecting the mask itself.
This has been the best cross-browser way I've found to apply a mask, but I'm uncertain how to apply CSS animations to it in such a way I can have the center image rotate inside the mask, and not both at the same time.
For example, my current code just rotates the entire image and mask together.
HTML
<div class="svgMask">
<svg width="726" height="726" baseProfile="full" version="1.2">
<defs>
<mask id="svgmask2" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse" transform="scale(1)">
<image width="100%" height="100%" xlink:href="http://www.mikerezl.com/img/testmask.png"/>
</mask>
</defs>
<image id="interior" mask="url(#svgmask2)" width="100%" height="100%" y="0" x="0" xlink:href="http://www.mikerezl.com/img/valknut.jpg"/>
</svg>
</div>
CSS
#interior {
-webkit-animation-name: rotate;
-webkit-animation-duration:2s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-timing-function:linear;
-moz-animation-name: rotate;
-moz-animation-duration:2s;
-moz-animation-iteration-count:infinite;
-moz-animation-timing-function:linear;
}
#-webkit-keyframes rotate {
from {-webkit-transform:rotate(0deg);}
to { -webkit-transform:rotate(360deg);}
}
#-moz-keyframes rotate {
from {-moz-transform:rotate(0deg);}
to { -moz-transform:rotate(360deg);}
}
Fiddle link
You need to set the origin like this (http://jsfiddle.net/icodeforlove/f5RE4/1/)
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
transform-origin: 50% 50%;
but for me performance is horrible and firefox isnt working. i would suggest using a canvas to composite your image and animating on that.
context.save();
context.drawImage(valknut, 0, 0);
context.globalCompositeOperation = 'destination-in';
context.drawImage(mask, 0, 0);
context.restore();
by using a canvas you gain a lot of control! heres an example of how you would achieve this with a canvas (http://jsfiddle.net/f5RE4/)

SVG rotate animation for recycle circle wobbly

This appears to be an issue with the Inkscape SVG output for my SVG image. The transform matrix seems to be causing a slight wobble of the circle. Since I am not nor ever will be mathematically inclined, I am stumped on how to correct this so it does not wobble.
I have tried both CSS3 animation as well as SVG animateTransform. Both act the same. I can alter the wobble by editing the transform matrix but it only gets worse.
I've only used the webkit proprietary css here for brevity.
I've created a fiddle here:
http://jsfiddle.net/slwfleming/KGZns/
<div class="box">
<div class="rotateme">
<svg class="refresh-status1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" xml:space="preserve" viewBox="0 0 18 18">
<g transform="translate(0,1.5)">
<g transform="matrix(3.239515,0,0,3.239515,-78.803548,-173.89306)">
<path d="m 28.973,54.655 -0.419,0.008 c 0.63,0.787 0.589,1.937 -0.14,2.667 -0.633,0.633 -1.583,0.746 -2.338,0.356 l -0.422,0.13 0.04,0.421 c 1.02,0.571 2.328,0.435 3.195,-0.433 0.968,-0.968 1.028,-2.489 0.2,-3.539 l -0.116,0.39 z"></path>
<path d="m 25.437,57.162 c -0.63,-0.787 -0.59,-1.937 0.141,-2.667 0.633,-0.633 1.583,-0.746 2.337,-0.355 l 0.422,-0.13 -0.039,-0.421 c -1.02,-0.572 -2.328,-0.435 -3.194,0.432 -0.97,0.97 -1.029,2.49 -0.201,3.54 l 0.115,-0.39 0.419,-0.009 z"></path>
</g>
</g>
</svg>
</div>
</div>
.box {
border:1px solid #c00;
width:2rem;
height:2rem;
position:relative;
}
#-webkit-keyframes rotateRefresh {
0% {
-webkit-transform: rotate(0deg) scaleX(1) scaleY(1) skewX(0deg) skewY(0deg);
}
100% {
-webkit-transform: rotate(360deg) scaleX(1) scaleY(1) skewX(0deg) skewY(0deg);
}
}
.rotateme {
width:35px;
height:35px;
-webkit-animation:rotateRefresh 4s linear infinite;
position:absolute;
top:0;
left:0;
}
.refresh-status1 {
width:35px;
height:35px;
}
Your SVG is not centred in its viewBox. You can see this if you extract it and add a contrasting background.
Demo here
Inkscape doesn't add viewBox attributes, so I am guessing you did this yourself?
If you tweak the width and height of the viewBox so it is correct (a tight fit around the diagram), it shouldn't wobble. Changing the "18" to "17.3" seems to work.
viewBox="0 0 17.3 17.3"
See corrected version here
It's also not quite centred properly in the viewBox (it's down and to the left very slightly), but that tiny error is not really visible in the final animation.

Resources