为什么 transform-origin 不适用于使用内联 SVG 的 Firefox,还有其他选择吗?
Why does transform-origin not work for Firefox using inline SVG and is there an alternative?
我发现 Firefox 与 Chrome、Edge 和 Opera 相比存在不一致之处。当使用 CSS class 时,每个浏览器都能很好地处理 transform-origin
。但是,当我将 transform-origin
作为属性放在 SVG 元素上时,FF 会忽略该效果。下面的演示代码。我的主要问题是如何解决这个问题,但我也很想知道这是否是预期的行为。
CSS transform-origin
在 FF 中工作。
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>
<style>
.centered{
transform-origin: center;
}
</style>
<path fill='#500' d='M500 500 400 400 400 600 600 600 600 400z' transform='scale(2)' class='centered'/>
</svg>
内联 SVG 似乎无法识别 transform-origin
(在 Chrome/edge 中始终有效)
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>
<path fill='#500' d='M500 500 400 400 400 600 600 600 600 400z' transform='scale(2)' transform-origin='center'/>
</svg>
编辑:另一位用户指出这个问题类似于 How to set transform origin in SVG,但他们的前提非常宽泛(如何做)并且错误或过时(8.5 年前发布)。
"I tried using the transform-origin attribute, but it does not affect
anything."
也许浏览器支持有所改进,但我的问题具体表明 transform-origin
在所有现代浏览器中作为 CSS 规则完美运行,或者在除 FireFox 之外的所有现代浏览器中作为表示属性完美运行。这种差异可能导致一个解决方案是该线程独有的,而第二个解决方案是对其他线程答案的新解决方案。
更不用说他们的问题围绕 JavaScript 实现,并且是在 FireFox 无法识别关键字 "center" 或无单位数字的时候发布的,这有损于核心 SVG 标记问题是 FireFox 解释表示属性 transform-origin=''
与其他浏览器不同。
我已经解决了这个问题,但我(到目前为止)无法给你一个全面的推理为什么它有效。
首先要知道的是,您可以 chain SVG Transforms.
所以,无论你在哪里写transform="scale(2)"
,你都可以在链中添加一个translate(x, y)
,像这样:
transform="scale(2) translate(x, y)"
到目前为止,很好...但是如果 scale
是 2
,那么我们应该给 [=21= 的 x
和 y
什么值]?
为了找出答案,我决定叠加更大和更小比例的 SVG 形状版本(彩虹的每种颜色一个),看看我能找到什么图案。
在你的 grey 形状的顶部,我放置了一个相同大小的 green 形状。
我给 green 形状一个变换:
transform="scale(1) translate(0, 0)"
以便它与您原来的 灰色 形状完全一致。
然后我着手对更大比例的版本进行子拼版(黄色、橙色、红色)并叠加较小比例的版本(blue、indigo、violet)。
我预测 x
和 y
在每种情况下都会与应用于该形状的 scale
因素以及原始 viewBox
的整体大小有关.
有了 3 个较小的版本和 3 个较大的版本,模式出现了:
- 红色,
8
倍大 / x
& y
转换值是 50% of ((1000 / 8) - 1000)
- 橙色,
4
倍大/x
& y
转换值是50% of ((1000 / 4) - 1000)
- 黄色,
2
倍大/x
&y
变换值是50% of ((1000 / 2) - 1000)
- 绿色,
1
倍大/x
& y
转换值是50% of ((1000 / 1) - 1000)
- Blue,
0.5
倍大/x
& y
转换值是 50% of ((1000 / 0.5) - 1000)
- Indigo,
0.25
倍大 / x
& y
转换值是 50% of ((1000 / 0.25) - 1000)
- Violet,
0.125
倍大 / x
& y
转换值是 50% of ((1000 / 0.125) - 1000)
据此,我们可以得出结论,如果您将一个形状定位在 viewBox
的 50%, 50%
中心,并且您希望在 scale(2)
的相同位置显示该形状,您必须还申请translate
for x
of:
50% of ((width of canvas / scale-factor) - (width of canvas))
其中 50%
对应于您希望形状居中的 x
位置。
translate
y
的
50% of ((height of canvas / scale-factor) - (height of canvas))
其中 50%
对应于您希望形状居中的 y
位置。
它始终如一地工作,但我还没有花足够的时间盯着它看,以正确理解原因。
工作示例:
<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>
总的来说,标记为正确的答案在所有情况下都有效。但是,我正在编写另一个解决方案,因为它最容易实现。但请注意,它仅适用于 transform
而不适用于 patternTransform
。虽然非 FireFox 浏览器可以识别 transform-origin
这两个属性,但我的解决方案不适用于 FireFox 上的 patternTransform
。
在样式属性 (style='transform-origin:center'
) 中添加 transform-origin
而不是其自己的表示属性 (transform-origin='center'
) 适用于 transform
,如下所示。这甚至适用于数据 URI 中的 SVG。
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>
<path fill='#500' d='M500 500 400 400 400 600 600 600 600 400z' transform='scale(2)' style='transform-origin:center'/>
</svg>
我发现 Firefox 与 Chrome、Edge 和 Opera 相比存在不一致之处。当使用 CSS class 时,每个浏览器都能很好地处理 transform-origin
。但是,当我将 transform-origin
作为属性放在 SVG 元素上时,FF 会忽略该效果。下面的演示代码。我的主要问题是如何解决这个问题,但我也很想知道这是否是预期的行为。
CSS transform-origin
在 FF 中工作。
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>
<style>
.centered{
transform-origin: center;
}
</style>
<path fill='#500' d='M500 500 400 400 400 600 600 600 600 400z' transform='scale(2)' class='centered'/>
</svg>
内联 SVG 似乎无法识别 transform-origin
(在 Chrome/edge 中始终有效)
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>
<path fill='#500' d='M500 500 400 400 400 600 600 600 600 400z' transform='scale(2)' transform-origin='center'/>
</svg>
编辑:另一位用户指出这个问题类似于 How to set transform origin in SVG,但他们的前提非常宽泛(如何做)并且错误或过时(8.5 年前发布)。
"I tried using the transform-origin attribute, but it does not affect anything."
也许浏览器支持有所改进,但我的问题具体表明 transform-origin
在所有现代浏览器中作为 CSS 规则完美运行,或者在除 FireFox 之外的所有现代浏览器中作为表示属性完美运行。这种差异可能导致一个解决方案是该线程独有的,而第二个解决方案是对其他线程答案的新解决方案。
更不用说他们的问题围绕 JavaScript 实现,并且是在 FireFox 无法识别关键字 "center" 或无单位数字的时候发布的,这有损于核心 SVG 标记问题是 FireFox 解释表示属性 transform-origin=''
与其他浏览器不同。
我已经解决了这个问题,但我(到目前为止)无法给你一个全面的推理为什么它有效。
首先要知道的是,您可以 chain SVG Transforms.
所以,无论你在哪里写transform="scale(2)"
,你都可以在链中添加一个translate(x, y)
,像这样:
transform="scale(2) translate(x, y)"
到目前为止,很好...但是如果 scale
是 2
,那么我们应该给 [=21= 的 x
和 y
什么值]?
为了找出答案,我决定叠加更大和更小比例的 SVG 形状版本(彩虹的每种颜色一个),看看我能找到什么图案。
在你的 grey 形状的顶部,我放置了一个相同大小的 green 形状。
我给 green 形状一个变换:
transform="scale(1) translate(0, 0)"
以便它与您原来的 灰色 形状完全一致。
然后我着手对更大比例的版本进行子拼版(黄色、橙色、红色)并叠加较小比例的版本(blue、indigo、violet)。
我预测 x
和 y
在每种情况下都会与应用于该形状的 scale
因素以及原始 viewBox
的整体大小有关.
有了 3 个较小的版本和 3 个较大的版本,模式出现了:
- 红色,
8
倍大 /x
&y
转换值是50% of ((1000 / 8) - 1000)
- 橙色,
4
倍大/x
&y
转换值是50% of ((1000 / 4) - 1000)
- 黄色,
2
倍大/x
&y
变换值是50% of ((1000 / 2) - 1000)
- 绿色,
1
倍大/x
&y
转换值是50% of ((1000 / 1) - 1000)
- Blue,
0.5
倍大/x
&y
转换值是50% of ((1000 / 0.5) - 1000)
- Indigo,
0.25
倍大 /x
&y
转换值是50% of ((1000 / 0.25) - 1000)
- Violet,
0.125
倍大 /x
&y
转换值是50% of ((1000 / 0.125) - 1000)
据此,我们可以得出结论,如果您将一个形状定位在 viewBox
的 50%, 50%
中心,并且您希望在 scale(2)
的相同位置显示该形状,您必须还申请translate
for x
of:
50% of ((width of canvas / scale-factor) - (width of canvas))
其中 50%
对应于您希望形状居中的 x
位置。
translate
y
的
50% of ((height of canvas / scale-factor) - (height of canvas))
其中 50%
对应于您希望形状居中的 y
位置。
它始终如一地工作,但我还没有花足够的时间盯着它看,以正确理解原因。
工作示例:
<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>
总的来说,标记为正确的答案在所有情况下都有效。但是,我正在编写另一个解决方案,因为它最容易实现。但请注意,它仅适用于 transform
而不适用于 patternTransform
。虽然非 FireFox 浏览器可以识别 transform-origin
这两个属性,但我的解决方案不适用于 FireFox 上的 patternTransform
。
在样式属性 (style='transform-origin:center'
) 中添加 transform-origin
而不是其自己的表示属性 (transform-origin='center'
) 适用于 transform
,如下所示。这甚至适用于数据 URI 中的 SVG。
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'>
<path fill='#500' d='M500 500 400 400 400 600 600 600 600 400z' transform='scale(2)' style='transform-origin:center'/>
</svg>