与 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 0pxtransform-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>