27

I am having an issue with getting transform-origin to work in Firefox (v.18+, other versions not tested). Webkit browsers work as expected. I'm trying to set the origin to the center of the group, but nothing I've tried has worked so far.

Here's the code:

#test {
  -webkit-transform-origin: 50% 50%;
  transform-origin: center center;
  -webkit-animation: prop 2s infinite;
  animation: prop 2s infinite;
}

@-webkit-keyframes prop {
  0% {
    -webkit-transform: scale(1, 1);
  }
  20% {
    -webkit-transform: scale(1, .8);
  }
  40% {
    -webkit-transform: scale(1, .6);
  }
  50% {
    -webkit-transform: scale(1, .4);
  }
  60% {
    -webkit-transform: scale(1, .2);
  }
  70% {
    -webkit-transform: scale(1, .4);
  }
  80% {
    -webkit-transform: scale(1, .6);
  }
  90% {
    -webkit-transform: scale(1, .8);
  }
  100% {
    -webkit-transform: scale(1, 1);
  }
}

@keyframes prop {
  0% {
    transform: matrix(1, 0, 0, 1, 0, 0);
  }
  20% {
    transform: matrix(1, 0, 0, .8, 0, 0);
  }
  40% {
    transform: matrix(1, 0, 0, .6, 0, 0);
  }
  50% {
    transform: matrix(1, 0, 0, .4, 0, 0);
  }
  60% {
    transform: matrix(1, 0, 0, .2, 0, 0);
  }
  70% {
    transform: matrix(1, 0, 0, .4, 0, 0);
  }
  80% {
    transform: matrix(1, 0, 0, .6, 0, 0);
  }
  90% {
    transform: matrix(1, 0, 0, .8, 0, 0);
  }
  100% {
    transform: matrix(1, 0, 0, 1, 0, 0);
  }
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128px" height="128px" viewBox="0 0 16 16">
    <g id="test">
        <rect fill="#404040" x="7.062" y="3.625" width="1.875" height="8.75"/>
    </g>
</svg>
leonheess
  • 16,068
  • 14
  • 77
  • 112
kevinstueber
  • 2,926
  • 3
  • 26
  • 26
  • FWIW, supposedly fixed as of Firefox 19 beta 3, though I'm still having problems in Firefox 22. Mozilla bugzilla listing: https://bugzilla.mozilla.org/show_bug.cgi?id=828286 – Toph Jul 08 '13 at 05:14
  • Ugh nvm sorry misread, I'm not sure that bug's related... – Toph Jul 08 '13 at 07:11
  • 3
    transform-origin is not supported for SVG elements in Firefox. Please up vote [bug #923193)](https://bugzilla.mozilla.org/show_bug.cgi?id=923193) to get it supported. – dotnetCarpenter May 21 '14 at 09:32
  • @dotnetCarpenter it's now fixed with Firefox 41+ – zigomir Aug 25 '15 at 13:33
  • @zigomir yes you're right! It is still not the default firefox browser yet though. But yes, the issue will go away with the next firefox release. Test: https://bug1013421.bmoattachments.org/attachment.cgi?id=8425610 – dotnetCarpenter Sep 11 '15 at 10:42

8 Answers8

24

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.

fregante
  • 29,050
  • 14
  • 119
  • 159
Websemantic
  • 404
  • 7
  • 13
  • 2
    For those running into the same problem, this answer is helpful. If you are trying to apply the animation on a element it still may not work with Firefox. There is a handy fix here: http://stackoverflow.com/a/18943090/1869285 – Fingel Sep 25 '13 at 20:38
  • 1
    Firefox v42 now supports the -moz-transform-origin tag. – voam Nov 05 '15 at 15:05
  • Smart way to do it. Wish firefox would get their poopsies together. – Marcos Pereira Mar 30 '16 at 21:49
  • Here's a Codepen to prove your point (without any Javascript). Thanks for the tip. :) https://codepen.io/schafeld/pen/zwjodP – Oliver Schafeld May 12 '17 at 17:08
23

As of Firefox 55 (released August 8, 2017), the "transform-box" CSS property is now supported. Setting it to "fill-box" will mimic that of Chrome with respect to transform-origin in SVG trees.

transform-origin: center; /* or transform-origin: 50% */
transform-box: fill-box;

Update 2017-9-14

You can select the elements that you need within the SVG structure or, as Tom points out in the comments, you can simply apply it to all decendants of the SVG element (as long as the styling does not interfere with anything else you are attempting to achieve):

svg .my-transformed-element {
    transform-origin: center; /* or transform-origin: 50% */
    transform-box: fill-box;
}

or

svg * {
    transform-origin: center; /* or transform-origin: 50% */
    transform-box: fill-box;
}
Jim
  • 3,210
  • 2
  • 17
  • 23
  • Please edit your answer to indicate _on what element(s)_ this CSS prop should be set. (SVG? G? Path/Rect/etc) Is it like HTML `box-sizing`, so we want `svg * { transform-box: fill-box; }` ? EDIT: I ended up doing the latter. `svg * {}` – Tom Sep 14 '17 at 19:36
  • Updated, and thanks for the info Tom! - As far as the element, it can be any elements within the SVG structure that you need the styling on (such as doing an animation) - ``, ``, ``, whatever. – Jim Sep 14 '17 at 21:23
  • 2
    This should be the accepted answer. Just a simple `svg * { transform-box: fill-box; }` fixed all animations for me. – Husky Sep 27 '17 at 13:53
  • This should be the answer now! – Megaroeny Apr 24 '18 at 20:19
  • I wish this transform-box: fill-box worked but it doesn't appear to: https://codepen.io/MSCAU/pen/XyXoba. Am I missing something? – MSC Nov 08 '18 at 06:14
  • @MSC - The rotate transform is not rotating around the point you think it is. You can add half a pixel to compensate: https://codepen.io/jimbo2150/pen/VVgWGj – Jim Dec 01 '18 at 16:35
  • @Jim - yes. Most of the time people don't use such small units with SVG so it goes unnoticed. Firefox team has noted it as a bug and ranked it as priority 3: https://bugzilla.mozilla.org/show_bug.cgi?id=1505932 – MSC Dec 01 '18 at 23:17
  • 1
    @MSC - After doing some testing I thought it might be a bug but I was not sure. Thanks. – Jim Dec 02 '18 at 14:32
8

@PatrickGrey's answer worked perfectly for me, but I needed to handle a much more complex SVG with several paths. I was able to accomplish this fix using Inkscape, but it was a multi-step process. I recommend doing this with the Inkscape XML Editor open so you can watch what's happening.

  1. Select the elements you want to transform and choose Object > Group to make a new group. Drag this group so that it is centered over the top left corner of the document. This applies a transform="translate(…, …)" attribute to the group.

  2. Choose Object > Ungroup from the menu. This will "flatten" the transform attribute, applying any coordinate transformations to the elements in the group.

  3. The original elements should still be selected. Choose Object > Group to put them back into a group. If you are using CSS to transform the elements, add your ID or class attribute to this group (The XML editor comes in handy for this bit, or you can modify the group's ID by right-clicking it and choosing Object Properties. Classes will need to be added through the XML editor or later in your text editor.).

  4. With the group selected, choose Object > Group again. This creates a new group around the original group.

  5. Drag this new group to the correct location in the document. If you inspect the DOM using the XML editor, you'll see the transform="translate(…, …)" is added to the outer group.

  6. Any CSS transforms can now be applied to the inner group, and they will be handled consistently by Chrome and Firefox.

Thanks to @PatrickGrey.co.uk for the initial insight. The trickiest part was figuring out how to apply the initial transform to the complex object's coordinates without resorting to hair pulling and extensive maths. The "Group, move, Ungroup" trick was documented a few places on StackOverflow, but I'd forgotten it until today. Hopefully these steps can save someone else a fair amount of grief.

thirdender
  • 3,891
  • 2
  • 30
  • 33
6

According to the comments in this bug report, Firefox's default value for transform-box is different than Chrome's. As of Firefox 55, this property can now be set without setting a flag.

This fixed the issue for me:

transform-box: fill-box;
transform-origin: center center;
ksav
  • 20,015
  • 6
  • 46
  • 66
LandonSchropp
  • 10,084
  • 22
  • 86
  • 149
1

If you can use a fixed pixel value, use that instead to make it work.

-moz-transform-origin: 25px 25px;
-ms-transform-origin:  25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin:  25px 25px;
transform-origin: 25px 25px;

Some browsers still don't support transform-origin with percentage values the way they should – at least not in all situations. If you don't have a fixed px value calculate one per javascript and use the library of your choice (like jQuery,Greensock,etc) to set the value.

Hafenkranich
  • 1,696
  • 18
  • 32
0

FWIW, I was able to solve my problem with Greensock, using TweenMax to animate individual paths inside, and this worked in Firefox Gecko, and Webkit browsers (Safari/Chrome) It does a better job of calculating the origin (not exactly sure how, but it worked for me)

Had an SVG with two gears I wanted to rotate inside another shape. So I gave each gear a unique id (id="gear1", id="gear2") and then rotated them with Greensock, something like this:

TweenMax.to("#gear1", 3.2, { 
  repeat: -1, //repeat infintely 
  ease: Linear.easeNone,  //no easing, linear motion 
  rotation:360,  //amount to rotate (full) 
  transformOrigin:"center"  //transform origin that WORKS :) 
});

Same for #gear2 with slightly different timing, and works great across browsers.

Jesse
  • 11
  • 4
0

Is missing the -moz-transform-origin from your css code.

#test{
    -webkit-transform-origin: 50% 50%;
    -moz-transform-origin: 50% 50%;
    ...
}
Andrei Todorut
  • 4,260
  • 2
  • 17
  • 28
0

As an addition, you might consider disabling the animation for Firefox versions which don't support transform-box: fill-box

Like this:

@supports (-moz-transform: rotate(0deg)) and (not (transform-box: fill-box)) {
    #test {
        animation: none;
    }
}

The first statement is just to check if you're on firefox, since you don't want to disable it on other browsers anyway. The second statement checks if the transform-box-property is supported by the browser. I used this in a current project and it works like a charm.

SoBiT
  • 408
  • 5
  • 18