与 Blink 和 Gecko 相比,为什么 Webkit/Safari(iOS,macOS)以不同的顺序呈现我的 SVG 转换?
Why does Webkit/Safari (iOS, macOS) render my SVG transformations in a different order compared to Blink and Gecko?
我有一个星号图标的最小 SVG 图像:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs>
<style>
.a {
fill: red;
transform-box: fill-box;
transform-origin: center;
}
</style>
</defs>
<!-- x = 45 because it's 10px wide and centered around x=50, so x0 == 45, x1 == 55 -->
<rect class="a" x="45" y="0" width="10" height="100"/>
<rect class="a" x="45" y="0" width="10" height="100" transform="rotate(-45)"/>
<rect class="a" x="45" y="0" width="10" height="100" transform="rotate( 45)"/>
<rect class="a" x="45" y="0" width="10" height="100" transform="rotate(-90)"/>
</svg>
这在 Firefox 75 和 Chrome 80 中正确呈现,但在 iOS 和 macOS 上无法正确呈现 Safari:
火狐 75:
Chrome 80:
Safari 在 iOS 13
但是在 Safari 上,transform-origin
似乎被忽略了,或者与每个 <rect>
元素上的 transform=""
属性相比乱序应用:
有人告诉我它在 macOS Safari 上渲染了相同的损坏图像(我现在无法立即访问 macOS Safari,所以我无法从那里 post 截图,抱歉)。
我搜索了 Google 以查看 Safari/WebKit 是否缺乏对 transform-box
, transform-origin
or transform="rotate(deg)"
的支持,但据我所知,Safari 多年来一直全力支持它们- 所以我不明白为什么它会乱序应用转换并导致渲染中断。
在 Safari 中摆弄 SVG 之后,Safari 的 Web Inspector 确实 似乎可以识别 transform-origin
SVG 样式 属性,但实际上并不在应用转换时使用它,这很奇怪(例如使用 transform-origin: center;
或 transform-origin: 0px 0px
或 transform-origin: 50px 50px
没有效果) - 因此解决方法在于使用其他方式更改旋转中心。
据我所知,macOS Safari 和 iOS Safari 都只使用 transform-origin
进行基于 CSS 的转换,使用 transform
属性和 not 当使用 transform=""
使用基于 SVG 属性的转换时 - 而 Blink 和 Gecko 都使用 transform-origin
用于基于属性和基于 CSS转换。
使用 translate
步骤
一种方法是添加 translate
步骤,使旋转中心位于 canvas 的中心,然后执行旋转,然后撤消 translate
步骤:
transform="translate( 50, 50 ) rotate(45) translate( -50, -50 )"
像这样:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<rect fill="red" x="45" y="0" width="10" height="100" />
<rect fill="blue" x="45" y="0" width="10" height="100" transform="translate(50,50) rotate(-45) translate(-50,-50)" />
<rect fill="green" x="45" y="0" width="10" height="100" transform="translate(50,50) rotate( 45) translate(-50,-50)" />
<rect fill="orange" x="45" y="0" width="10" height="100" transform="translate(50,50) rotate(-90) translate(-50,-50)" />
</svg>
更好的方法:使用 rotate( angle, x, y )
:
I saw that the rotate
transformation function 支持使用附加参数指定旋转中心,而不是对 transform
链应用初始 translate
步骤,因此这在 Safari 中有效,Chrome (+Edge +Opera), 和 Firefox:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<rect fill="red" x="45" y="0" width="10" height="100" />
<rect fill="blue" x="45" y="0" width="10" height="100" transform="rotate(-45, 50, 50)" />
<rect fill="green" x="45" y="0" width="10" height="100" transform="rotate( 45, 50, 50)" />
<rect fill="orange" x="45" y="0" width="10" height="100" transform="rotate(-90, 50, 50)" />
</svg>
我有一个星号图标的最小 SVG 图像:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs>
<style>
.a {
fill: red;
transform-box: fill-box;
transform-origin: center;
}
</style>
</defs>
<!-- x = 45 because it's 10px wide and centered around x=50, so x0 == 45, x1 == 55 -->
<rect class="a" x="45" y="0" width="10" height="100"/>
<rect class="a" x="45" y="0" width="10" height="100" transform="rotate(-45)"/>
<rect class="a" x="45" y="0" width="10" height="100" transform="rotate( 45)"/>
<rect class="a" x="45" y="0" width="10" height="100" transform="rotate(-90)"/>
</svg>
这在 Firefox 75 和 Chrome 80 中正确呈现,但在 iOS 和 macOS 上无法正确呈现 Safari:
火狐 75:
Chrome 80:
Safari 在 iOS 13
但是在 Safari 上,transform-origin
似乎被忽略了,或者与每个 <rect>
元素上的 transform=""
属性相比乱序应用:
有人告诉我它在 macOS Safari 上渲染了相同的损坏图像(我现在无法立即访问 macOS Safari,所以我无法从那里 post 截图,抱歉)。
我搜索了 Google 以查看 Safari/WebKit 是否缺乏对 transform-box
, transform-origin
or transform="rotate(deg)"
的支持,但据我所知,Safari 多年来一直全力支持它们- 所以我不明白为什么它会乱序应用转换并导致渲染中断。
在 Safari 中摆弄 SVG 之后,Safari 的 Web Inspector 确实 似乎可以识别 transform-origin
SVG 样式 属性,但实际上并不在应用转换时使用它,这很奇怪(例如使用 transform-origin: center;
或 transform-origin: 0px 0px
或 transform-origin: 50px 50px
没有效果) - 因此解决方法在于使用其他方式更改旋转中心。
据我所知,macOS Safari 和 iOS Safari 都只使用 transform-origin
进行基于 CSS 的转换,使用 transform
属性和 not 当使用 transform=""
使用基于 SVG 属性的转换时 - 而 Blink 和 Gecko 都使用 transform-origin
用于基于属性和基于 CSS转换。
使用 translate
步骤
一种方法是添加 translate
步骤,使旋转中心位于 canvas 的中心,然后执行旋转,然后撤消 translate
步骤:
transform="translate( 50, 50 ) rotate(45) translate( -50, -50 )"
像这样:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<rect fill="red" x="45" y="0" width="10" height="100" />
<rect fill="blue" x="45" y="0" width="10" height="100" transform="translate(50,50) rotate(-45) translate(-50,-50)" />
<rect fill="green" x="45" y="0" width="10" height="100" transform="translate(50,50) rotate( 45) translate(-50,-50)" />
<rect fill="orange" x="45" y="0" width="10" height="100" transform="translate(50,50) rotate(-90) translate(-50,-50)" />
</svg>
更好的方法:使用 rotate( angle, x, y )
:
I saw that the rotate
transformation function 支持使用附加参数指定旋转中心,而不是对 transform
链应用初始 translate
步骤,因此这在 Safari 中有效,Chrome (+Edge +Opera), 和 Firefox:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
<rect fill="red" x="45" y="0" width="10" height="100" />
<rect fill="blue" x="45" y="0" width="10" height="100" transform="rotate(-45, 50, 50)" />
<rect fill="green" x="45" y="0" width="10" height="100" transform="rotate( 45, 50, 50)" />
<rect fill="orange" x="45" y="0" width="10" height="100" transform="rotate(-90, 50, 50)" />
</svg>