Transform-Origin Not Working on Firefox

transform-origin not working on firefox

A I mentioned in the comments FF has a different interpretation of transform-origin (at least as i understand it) but I've done some extra (quick) research since that comment. The linked article https://css-tricks.com/svg-animation-on-css-transforms/ has a wealth of information.

Chrome uses 50% 50 to be related the the center of the object being transformed.

Firefox uses 50% 50% to be related to the center of the SVG parent.

Therefore top left for Chrome would translate in Firefox to Xpx Ypx where X and Y are the top left co-ordinates of the transformed element.

So...for the right arm

<g id="right-arm" class="arm-wave">
<rect id="right-hand" x="375.6" y="403.9" class="skin-color" width="46.5" height="16.8"/>
<rect id="right-el" **x="375.6" y="249.8" class="sweater-color" width="46.5" height="151.6"/>
</g>

We would use...

transform-origin: 375.6px 249.8px;
-webkit-transform-origin: top left;

JSfiddle Demo

Why does transform-origin not work for Firefox using inline SVG and is there an alternative?

I've solved the problem but I am (as yet) unable to give you a comprehensive reasoning why it works.

The first important thing to know is that you can chain SVG Transforms.

So, wherever you write transform="scale(2)", you can add a translate(x, y) to the chain, like this:

transform="scale(2) translate(x, y)"

So far, so good... but if scale is 2, then what values should we give to x and y of translate?

To find out, I decided to superimpose larger and subimpose smaller scaled versions of your SVG shape (one for each colour of the rainbow) and see what patterns I could find.

Over the top of your grey shape, I positioned an identically sized green shape.

I gave the green shape a transform of:

transform="scale(1) translate(0, 0)"

so that it would be exactly congruent with your original grey shape.

Then I set about subimposing larger scaled versions (yellow, orange, red) and superimposing smaller scaled versions (blue, indigo, violet).

I predicted that x and y in each case would relate to the scale factor applied to that shape and also to the overall size of the original viewBox.

With 3 smaller versions and 3 larger versions, the pattern emerged:

  • Red, 8 times as large / x & y transform value is 50% of ((1000 / 8) - 1000)
  • Orange, 4 times as large / x & y transform value is 50% of ((1000 / 4) - 1000)
  • Yellow, 2 times as large / x & y transform value is 50% of ((1000 / 2) - 1000)
  • Green, 1 times as large / x & y transform value is 50% of ((1000 / 1) - 1000)
  • Blue, 0.5 times as large / x & y transform value is 50% of ((1000 / 0.5) - 1000)
  • Indigo, 0.25 times as large / x & y transform value is 50% of ((1000 / 0.25) - 1000)
  • Violet, 0.125 times as large / x & y transform value is 50% of ((1000 / 0.125) - 1000)

From this, we can conclude, that if you are positioning a shape centered at 50%, 50% of your viewBox and you want to display the shape in that same position with scale(2), you must also apply a translate for x of:

50% of ((width of canvas / scale-factor) - (width of canvas))

where 50% corresponds to the x position you want to centre the shape over.

And a translate for y of:

50% of ((height of canvas / scale-factor) - (height of canvas))

where 50% corresponds to the y position you want to centre the shape over.

This works consistently, but I haven't spent enough time staring at it yet, to properly understand why.

Working Example:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
<!-- Grey Original --><path fill="#555" d="M500 500 400 400 400 600 600 600 600 400z" />
<!-- Red Transform [50% of ((1000 / 8) - 1000) is -437.5] --><path fill="rgb(255, 0, 0)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(8) translate(-437.5, -437.5)" />
<!-- Orange Transform [50% of ((1000 / 4) - 1000) is -375] --><path fill="rgb(255, 125, 0)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(4) translate(-375, -375)" />
<!-- Yellow Transform [50% of ((1000 / 2) - 1000) is -250] --><path fill="rgb(255, 255, 0)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(2) translate(-250, -250)" />
<!-- Green Transform [50% of ((1000 / 1) - 1000) is 0] --><path fill="rgb(0, 125, 0)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(1) translate(0, 0)" />
<!-- Blue Transform [50% of ((1000 / 0.5) - 1000) is 500] --><path fill="rgb(0, 0, 125)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(0.5) translate(500, 500)" />
<!-- Indigo Transform [50% of ((1000 / 0.25) - 1000) is 1500] --><path fill="rgb(63, 0, 255)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(0.25) translate(1500, 1500)" />
<!-- Violet Transform [50% of ((1000 / 0.125) - 1000) is 3500] --><path fill="rgb(199, 125, 243)" d="M500 500 400 400 400 600 600 600 600 400z" transform="scale(0.125) translate(3500, 3500)" />
</svg>

svg transform-origin problems in firefox

Firefox is behaving correctly as per the spec. Chrome implemented transform-origin early before the spec finalised. It handles percentage values differently to what the final spec specified. AFAIK they have not fixed that yet.

If you want your animation to be compatible with all browsers, don't use percentage values in transform-origin.

transform-origin: 3246px 6271px;

http://codepen.io/anon/pen/MbrWod

Setting transform-origin on SVG group not working in Firefox

I was attempting to rotate a simple cog svg graphic around its centre point using a CSS transition. I had the same problem as you with Firefox; transform-origin seemed to have no effect.

The solution was to draw the original svg shape so that its centre was at coordinate 0, 0:

<svg x="0px" y="0px" width="400px" height="400px" viewBox="0 0 400 400">
<rect id="myObject" x="-50" y="-50" fill="#E52420" width="100" height="100"/>
</svg>

Then add a group around it and translate to the position you want:

<svg x="0px" y="0px" width="400px" height="400px" viewBox="0 0 400 400">
<g transform="translate(150, 100)">
<rect id="myObject" x="-50" y="-50" fill="#E52420" width="100" height="100"/>
</g>
</svg>

Now you can apply css transitions that should work in Firefox (I add a class to the HTML tag using JavaScript based on a user action (js-rotateObject) and use Minimizr to check that the browser can handle transforms and transitions (.csstransforms.csstransitions):

#myObject{
transform: rotate(0deg);
transition: all 1s linear;
}

.csstransforms.csstransitions.js-rotateObject #myObject{
transform: rotate(360deg);
}

Hope that helps.

SVG and FIREFOX and transform origin, why not working?

Firefox has the correct behaviour according to the spec. For SVG elements "transform-origin: center" means the centre of the SVG. Chrome has implemented an older version of the spec and is now technically wrong.

In the future, you'll be able to set the box used to calculate percentage (center = 50%) origin values, with the transform-box property.

Until then, if you want compatibility between browsers, you'll need to use absolute coordinates.

transform-origin: 421px 250px;

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"  width="696.667px" height="428.666px" viewBox="0 0 696.667 428.666" enable-background="new 0 0 696.667 428.666"  xml:space="preserve">
<style>
#coffeeFlower { -webkit-animation-name: coffeeFlower-animation; animation-name: coffeeFlower-animation; -webkit-animation-duration: 20s; animation-duration: 20s; -webkit-animation-iteration-count: infinite; animation-iteration-count: infinite; -webkit-transform-origin: 421px 250px; -ms-transform-origin: 421px 250px; transform-origin: 421px 250px; -webkit-animation-timing-function: linear; animation-timing-function: linear; }
@-webkit-keyframes coffeeFlower-animation { 0% {-webkit-transform: rotate(0deg);transform: rotate(0deg);} 100% {-webkit-transform: rotate(360deg);transform: rotate(360deg);} }
@keyframes coffeeFlower-animation { 0% {-webkit-transform: rotate(0deg);transform: rotate(0deg);} 100% {-webkit-transform: rotate(360deg);transform: rotate(360deg);} }
</style>

<g> <g> <g> <g> <path fill="#FF00CD" d="M402.577,58.794c135.259-11.36,221.089,81.12,232.3,157.827 c9.135,62.505-17.688,206.188-222.337,207.712c-204.65,1.523-207.344-171.682-207.243-205.123 C205.399,185.767,241.826,72.295,402.577,58.794z"/> <path fill="#9B009B" d="M400.396,115.509c45.462-1.239,113.712-17.373,126.306-46.262 c12.594-28.891-57.617-51.955-128.93-50.012c-71.313,1.944-114.239,30.769-113.681,51.271 C284.65,91.009,324.625,117.573,400.396,115.509"/> <path fill="#FF00CD" d="M394.548,3.81c11.438-1.887,25.438,1.115,26.92,12.675c1.482,11.56-11.712,13.737-16.993,14.609 c-8.362,1.38-19.837-0.618-24.626-8.452C373.64,12.485,386.072,5.208,394.548,3.81z"/> <path fill="#FF00CD" d="M227.215,307.564c0,0-50.859-0.397-61.369-25.981s-4.278-58.761-19.869-74.393 c-15.591-15.633-22.577-10.09-23.638-16.306s8.574-12.723,17.439-14.749c8.866-2.025,25.924,1.971,33.274,9.799 s19.619,32.472,35.664,32.034c16.045-0.437,29.351,29.53,30.704,46.443S227.215,307.564,227.215,307.564z"/> <path fill="#FF00CD" d="M600.25,149.313c0,0,38.16-7.285,68.258,16.873c30.097,24.158,30.396,67.861,11.344,88.898 c-12.95,14.299-49.288,24.537-49.288,24.537l0.859-33.922c0,0,26.791,1.053,30.665-20.462 c3.874-21.516-2.754-35.608-13.646-42.448s-30.479-5.414-30.479-5.414l-17.738-28.955"/> <path fill="#9B009B" d="M141.682,180.544c-4.545,0.125-15.033,4.871-14.068,7.521s13.493,4.093,22.383,2.958 c8.89-1.134,14.141-4.846,9.611-7.398C155.078,181.071,147.922,180.374,141.682,180.544z"/> </g> <path id="coffeeFlower" fill="#CDFF31" d="M436.924,236.235c0,0,35.948-25.799,9.224-56.801c-18.286-21.213-37.782-3.01-41.195,19.973 c-3.413,22.982,1.027,37.672,1.027,37.672s-6.398-37.141-37.238-32.453s-51.193,48.327-26.609,61.121s50.694,5.351,50.694,5.351 s-36.616,17.155-30.538,42.571c6.079,25.416,40.803,15.045,48.435-1.32c7.633-16.365,7.633-16.365,7.633-16.365 s12.673,36.734,36.975,30.996c24.302-5.738,26.406-27.338,19.312-40.608s-30.296-24.757-30.296-24.757s43.457,13.627,60.36-8.377 c16.904-22.003-5.356-48.324-24.119-45.121C461.827,211.321,436.924,236.235,436.924,236.235z"/> <path fill="#00FFFF" d="M411.361,236.933c0,0-17.852,11.93-10.048,26.528c7.803,14.598,25.147,8.739,32.29-0.88 C440.746,252.962,436.484,220.091,411.361,236.933z"/> </g> <g> <path fill="#FF00CD" d="M13.559,335.13c0,0,12.598-5.814,45.546-6.783c32.948-0.97,65.896,3.876,72.68,13.566 c6.784,9.69-4.845,82.37-62.989,82.37S2.899,358.387,3.869,350.634C4.838,342.882,4.838,338.036,13.559,335.13z"/> <path fill="#FF9B00" d="M13.559,343.851c-3.876,14.536,16.474,15.506,51.36,16.475s59.113-5.814,60.082-11.629 c0.969-5.814-27.025-9.889-41.67-10.66C64.919,337.067,15.325,337.229,13.559,343.851z"/> <path fill="#FF00CD" d="M129.847,358.387c0,0,18.412,6.784,21.319,19.382s0,24.227-10.66,29.071c-10.66,4.846-31.01,0-31.01,0 l6.783-14.536c0,0,16.474,9.691,22.289,0c5.814-9.69-10.66-22.288-10.66-22.288L129.847,358.387z"/> </g> <path id="kohviJuga" fill="#FF9B00" d="M135.634,190.937c0,0,3.591,1.055,10.046,0.43c6.455-0.627,9.624-1.438,9.624-1.438 s-4.441-26.975-10.921-40.859c-13.567-29.071-49.422-27.133-60.082-2.906c-7.364,16.735-20.35,202.533-20.35,202.533h19.381 c0,0,6.228-180,13.567-192.844c7.752-13.566,31.01-17.442,35.855,10.66C134.433,176.251,135.634,190.937,135.634,190.937z"/> </g> <path fill="#FF9B00" d="M55.229,315.748c0,0-5.814-30.04-16.474-25.195S55.229,315.748,55.229,315.748z"/> <path fill="#FF9B00" d="M91.084,322.532c0,0,0.969-10.66,6.784-9.691S91.084,322.532,91.084,322.532z"/></g></svg>

transform-origin not working in Firefox even properties in percentage value

To summarise the comments you have been getting:

  1. The transform-origin property with percentage values on SVG elements has been broken in Firefox, and has only just been fixed/implemented.

  2. The meaning of transform-origin: 50% 50% when applied to SVG elements has not been fully specified until recently. Chrome used the centre of the element's bounding box. Firefox uses the centre of the SVG.

  3. How percentage origins are to be calculated has only recently been decided. There is a new property called transform-box. See: https://drafts.csswg.org/css-transforms/#transform-box

The default value of transform-box for SVG elements is view-box (typically the centre of the whole SVG). However Chrome currently uses the equivalent of fill-box.

In summary, you should not rely on Chrome's behaviour. It is probably going to change to match what is specified by the new transform-box property.

If you want to have your SVG work now on both browsers, don't use percentage values in transform-origin. Use absolute coordinates. See example below.

.tyreA {  -webkit-transform-origin: 71.59px 43.42px;  -moz-transform-origin: 71.59px 43.42px;  transform-origin: 71.59px 43.42px;  transform: rotate(0);  -webkit-animation: spin 1s linear infinite;          animation: spin 1s linear infinite;}
.tyreB { -webkit-transform-origin: 19.83px 43.39px; -moz-transform-origin: 19.83px 43.39px; transform-origin: 19.83px 43.39px; transform: rotate(0); -webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite;}
.tyreC { -webkit-transform-origin: 51.2px 43.39px; -moz-transform-origin: 51.2px 43.39px; transform-origin: 51.2px 43.39px; transform: rotate(0); -webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite;}
@-webkit-keyframes spin { from { transform: rotate(360deg); } to { transform: rotate(0deg); }}@keyframes spin { from { transform: rotate(360deg); } to { transform: rotate(0deg); }}
<svg class='truck' viewBox='0 0 93 53' xmlns='http://www.w3.org/2000/svg' height="180">  <g class='chase' fill-rule='evenodd' fill='none'>    <path d='M32.087 35.263h3.023V5.973h-3.023v29.29z' fill='#EE7C00'></path>    <path d='M87.84 35.262H5.007v4.065L9.07 43.39h74.707l4.062-4.063v-4.065z' fill='#9B9B9B'></path>    <path d='M35.11 35.262h57.445v-3.966H35.11v3.966z' fill='#F09E00'></path>    <path d='M90.393 35.262h2.16v-3.966h-2.16v3.966z' fill='#E2000F'></path>    <path d='M17.498.493L2.91 15.08v20.182h29.175V.492H17.498z' fill='#FCC400'></path>    <path d='M29.495 2.905H18.16L6.823 14.24h22.67V2.905z' fill='#575656'></path>    <path d='M0 35.262h10.014v-3.966H0v3.966z' fill='#F09E00'></path>    <path d='M5.008 37.294h82.83v-2.032H5.01v2.032z' fill='#575656'></path>    <path d='M.75 29.858h2.16v-6.995H.75v6.995zM11.015 20.074h3.497v-2.16h-3.497v2.16z' fill='#E2000F'></path>    <path d='M28.447 35.262h1.05V14.24h-1.05v21.022z' fill='#EE7C00'></path>    <path d='M53.51 27.23h34.33v4.065H53.51V27.23z' fill='#575656'></path>  </g>  <g class='tyreA'>    <path d='M64.827 36.593a9.61 9.61 0 0 0 0 13.59c3.753 3.754 9.837 3.754 13.59 0a9.61 9.61 0 0 0-13.59-13.59' fill='#1A1A18'></path>    <path d='M67.287 39.053a6.13 6.13 0 0 0 0 8.67 6.13 6.13 0 1 0 0-8.67' fill='#9B9B9B'></path>    <path d='M67.287 39.053a6.133 6.133 0 0 0 0 8.67 6.134 6.134 0 0 0 8.67 0l-8.67-8.67z' fill='#C5C5C6'></path>    <path d='M68.784 40.55a4.012 4.012 0 0 0 5.676 5.677 4.012 4.012 0 0 0-5.676-5.676' fill='#868685'></path>    <path d='M65.526 37.293A8.62 8.62 0 1 1 77.72 49.486a8.62 8.62 0 0 1-12.192-12.193m-.385-.386c-3.578 3.578-3.578 9.384 0 12.963 3.58 3.58 9.385 3.58 12.964 0 3.578-3.58 3.578-9.385 0-12.963-3.58-3.58-9.386-3.58-12.964 0' fill='#3B3A39'></path>  </g>  <g class='tyreB'>    <path d='M13.038 36.593c-3.754 3.754-3.754 9.838 0 13.59a9.61 9.61 0 0 0 13.59 0c3.754-3.752 3.754-9.836 0-13.59a9.61 9.61 0 0 0-13.59 0' fill='#1A1A18'></path>    <path d='M15.498 39.054a6.128 6.128 0 0 0 0 8.67 6.13 6.13 0 0 0 8.67 0 6.13 6.13 0 0 0-8.67-8.67' fill='#9B9B9B'></path>    <path d='M15.498 39.054a6.13 6.13 0 1 0 8.67 8.67l-8.67-8.67z' fill='#C5C5C6'></path>    <path d='M16.996 40.55a4.012 4.012 0 1 0 5.675 5.677 4.014 4.014 0 0 0-5.674-5.676' fill='#868685'></path>    <path d='M13.737 37.293a8.622 8.622 0 0 1 12.192 0 8.622 8.622 0 0 1 0 12.192 8.622 8.622 0 0 1-12.193 0 8.622 8.622 0 0 1 0-12.192m-.385-.385a9.164 9.164 0 0 0 0 12.962c3.578 3.58 9.384 3.58 12.962 0a9.164 9.164 0 0 0 0-12.962 9.164 9.164 0 0 0-12.962 0' fill='#3B3A39'></path>  </g>  <g class='tyreC'>    <path d='M44.406 36.593c-3.753 3.754-3.753 9.838 0 13.59 3.754 3.755 9.838 3.755 13.59 0 3.755-3.752 3.755-9.836 0-13.59-3.752-3.753-9.836-3.753-13.59 0' fill='#1A1A18'></path>    <path d='M46.868 39.054a6.128 6.128 0 0 0 0 8.67 6.128 6.128 0 0 0 8.67 0 6.128 6.128 0 0 0 0-8.67 6.13 6.13 0 0 0-8.67 0' fill='#9B9B9B'></path>    <path d='M46.868 39.054a6.13 6.13 0 1 0 8.67 8.67l-8.67-8.67z' fill='#C5C5C6'></path>    <path d='M48.364 40.55a4.014 4.014 0 1 0 0 0' fill='#868685'></path>    <path d='M45.106 37.293a8.622 8.622 0 0 1 12.192 0 8.622 8.622 0 0 1 0 12.192 8.622 8.622 0 0 1-12.192 0 8.622 8.622 0 0 1 0-12.192m-.385-.385a9.164 9.164 0 0 0 0 12.962c3.58 3.58 9.385 3.58 12.963 0 3.58-3.578 3.58-9.384 0-12.962a9.164 9.164 0 0 0-12.962 0' fill='#3B3A39'></path>  </g></svg>

Transform origin on SVG pattern not working on Firefox/Safari

why not simply scaling the whole SVG:

* {  margin: 0;  padding: 0;}
svg { position:fixed; top:0; left:0; width:100%; height:100%; background: #0a0a0a; animation:zoom 3s ease-out forwards}
@keyframes zoom { to { transform:scale(3); }}
<svg ref="svg" xmlns:xlink="http://www.w3.org/1999/xlink" >    <defs>      <pattern        id="hexagons"        ref="pattern"        width="50"        height="43.4"        patternUnits="userSpaceOnUse"        patternTransform="rotate(90)"        x="50%"        y="50%"      >        <polygon          id="hex"          points="24.8,22 37.3,29.2 37.3,43.7 24.8,50.9 12.3,43.7 12.3,29.2"          fill="#0a0a0a"          stroke="#222"        />        <use xlink:href="#hex" x="25" />        <use xlink:href="#hex" x="-25" />        <use xlink:href="#hex" x="12.5" y="-21.7" />        <use xlink:href="#hex" x="-12.5" y="-21.7" />      </pattern>    </defs>    <rect id="mosaic" width="100%" height="100%" fill="url(#hexagons)" />  </svg>


Related Topics



Leave a reply



Submit