在Safari iOS 10中,SVG变换旋转圆形90度、180度或270度无法正常工作。

18

我希望使用SVG圆形元素设置stroke-dasharray和变化的stroke-dashoffset来创建甜甜圈图表。为了使图表“条形”从顶部开始,需要将SVG元素旋转270(或-90)度。以下是代码:

http://jsfiddle.net/q3wb6gkq/

旋转角度是在transform="rotate(270, 80, 80)"中的第一个数字指定的。
问题是:在iOS 10上使用Safari查看时,此旋转不起作用。实际上,设置90、180或270度旋转没有效果。同样的角度但为负数(例如-90)也不会被应用。
这是在iOS 10.0.1上在Safari中上述fiddle的截图:

iOS 10 screenshot

以下是在iOS 9.3.5上使用Safari浏览器的同样示例:

iOS 9 screenshot

作为一个解决方法,我发现使用约270.1度可以解决这个问题,但我想知道为什么270度不起作用以及是否有更好的处理方法。

无法重现此问题,但我怀疑这是因为圆没有特定的起点或终点。您可以通过将“transform”属性移动到封闭的<g>元素来修复它。如果这样不起作用,可以使用椭圆弧路径段创建一个圆形路径。 - r3mainer
谢谢 - 我已经尝试在一个包含<g>元素上设置相同的转换,但不幸的是这并没有帮助。我还没有尝试使用<path>,因为我想继续使用<circle>及其stroke-dasharray和stroke-dashoffset属性。当你说你无法重现这个问题时 - 你是指你在iOS 10设备上打开了fiddle,并且转换被正确应用了吗? - ilokhov
2
@squeamishossifrage 在 SVG 中,圆形确实有特定的起点/终点。它在3点钟方向 - Robert Longson
@RobertLongson 谢谢,我不知道那个。ilokhov:我只是没有相同的环境,仅此而已。 - r3mainer
我正在让我的圆从底部绘制,因此需要旋转90度。由于我用一个比圆的宽度大得多的节点(点)覆盖了起始点,所以现在我使用91度......但这让我不满意。我需要在iOS9.3上尝试一下。这可能只是Safari iOS 10的一个bug。目前还不确定。 - Erik
3个回答

6
我曾在iOS 10.1和Safari 10.0.1上痛苦地经历过这个问题。该错误肯定是由任何计算结果可被90度整除的rotate值触发的。
但更奇怪的是,该错误的存在受当前缩放级别的影响。
请查看我准备的此演示/一系列最小测试用例(jsFiddle版本here)。最好运行片段然后扩展到全屏:

svg {
  height: 80px;
  width: 80px;
}

circle {
  fill: none;
  stroke-dasharray: 150;
  stroke-width: 4px;
  stroke: #6fdb6f;
  transform-origin: center center;
}

.degrot {
  transform: rotate(-90deg);
}

.degrot-offset {
  transform: rotate(-90.1deg);
}

.degrot-offset-more {
  transform: rotate(-92deg);
}

.turnrot {
  transform: rotate(-0.25turn);
}

.turnrot-offset {
  transform: rotate(-0.251turn);
}


svg[viewBox] circle {
  stroke-dasharray: 300;
  stroke-width: 8px;
}

svg[viewBox].scaledown circle {
  stroke-dasharray: 300;
  stroke-width: 8px;
}

svg[viewBox].noscale circle {
  stroke-dasharray: 150;
  stroke-width: 4px;
}

svg[viewBox].scaleup circle {
  stroke-dasharray: 75;
  stroke-width: 2px;
}

.wc {
  will-change: transform;
}


/* Demo prettification */

p:last-child {
  margin-bottom: 0;
}

td {
  padding: 10px;
}

tr td:first-of-type {
  width: 80px;
  min-height: 80px;
}

tr + tr td {
  border-top: 1px solid #dcdcdc;
}
<table>
  <tr><td colspan="2">In Safari 10.0.1 and iOS 10.1, strange behavior can be observed on SVG shapes with <code>rotate</code> values not divisible by 90 degrees, when <code>transform-origin: center center;</code></td></tr>
  <tr>
    <td>

      <svg xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot" r="35" cy="40" cx="40" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-90deg);</code>
      <p>The stroke improperly begins <a href="https://www.w3.org/TR/SVG11/shapes.html#CircleElement">at 3:00</a>, as if the <code>transform</code> rule hadn't been applied.</p>
    </td>
  </tr>

  <tr>
    <td>

      <svg xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot-offset" r="35" cy="40" cx="40" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-90.1deg);</code>
      <p>The stroke begins at (twelve seconds before) 12:00, as expected.</p>
    </td>
  </tr>

  <tr>
    <td>

      <svg xmlns="http://www.w3.org/2000/svg">
        <circle class="turnrot" r="35" cy="40" cx="40" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-0.25turn);</code>
      <p>The same bug applies to any <code>rotate</code> value which computes to a multiple of 90 degrees.</p>
    </td>
  </tr>

  <tr>
    <td>

      <svg xmlns="http://www.w3.org/2000/svg">
        <circle class="turnrot-offset" r="35" cy="40" cx="40" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-0.251turn);</code>
      <p>43 seconds before noon.</p>
    </td>
  </tr>


  <tr><td colspan="2">But when the SVG element specifies a <code>viewBox</code> which is being scaled down, things can get weird:</td></tr>
  
  <tr>
    <td>

      <svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot" r="70" cy="80" cx="80" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-90deg);</code>
      <p>So far, so the same.</p>
    </td>
  </tr>

  <tr>
    <td>

      <svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot-offset" r="70" cy="80" cx="80" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-90.1deg);</code>
      <p>But now, offsetting by a little bit doesn't work, <em>unless</em> you zoom in the page in past a certain zoom threshold (either via pinching, or <code>View > Zoom</code> and/or keyboard shortcut). Try it; it's unsetting!</p>
      <p>This is probably because of some rounding of that the zooming engine performs, because...</p>
    </td>
  </tr>

  <tr>
    <td>

      <svg viewBox="0 0 160 160" class="scaledown" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot-offset-more" r="70" cy="80" cx="80" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-92deg);</code>
      <p>offsetting by a larger amount restores expected behavior.</p>
    </td>
  </tr>

  <tr><td colspan="2">If the SVG element is not being scaled <em>down</em>, behavior identical to the first section resumes. Zooming has no effect:</td></tr>
  
  <tr>
    <td>
      
      <svg viewBox="0 0 80 80" class="noscale" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot" r="35" cy="40" cx="40" />
      </svg>

      <svg viewBox="0 0 40 40" class="scaleup" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot" r="17.5" cy="20" cx="20" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-90deg);</code>
      <p>
      Top: No scaling (viewBox dimensions match parent element's)<br><br>
      Bottom: Scaling up (viewBox dimensions half of parent element's)
      </p>
    </td>
  </tr>

  <tr>
    <td>
      
      <svg viewBox="0 0 80 80" class="noscale" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot-offset" r="35" cy="40" cx="40" />
      </svg>

      <svg viewBox="0 0 40 40" class="scaleup" xmlns="http://www.w3.org/2000/svg">
        <circle class="degrot-offset" r="17.5" cy="20" cx="20" />
      </svg>

    </td>
    <td>
      <code>transform: rotate(-90.1deg);</code>
      <p>
        Top: No scaling (viewBox dimensions match parent element's)<br><br>
        Bottom: Scaling up (viewBox dimensions half of parent element's)
      </p>
    </td>
  </tr>

  <tr><td colspan="2">But there is one exception:</td></tr>

  <tr>
    <td>
      
      <svg class="degrot wc" xmlns="http://www.w3.org/2000/svg">
        <circle r="35" cy="40" cx="40" />
      </svg>

    </td>
    <td>
      <p>On the parent <code>svg</code> element:</p>
      <code>transform: rotate(-90deg);<br>will-change: transform;</code>
      <p>Iff the the the rotation is applied to a <em>parent</em> of the SVG shape (including the SVG element itself) along with the rule <code>will-change: transform</code>, all rotation values work as expected.</p>
    </td>
  </tr>

  <tr><td colspan="2">All these behaviors have been observed in Safari 10.0.1 and iOS 10.1. They appear to be fixed as of iOS 10.2 Beta 2.</td></tr>
</table>

正如演示中所述,在iOS 10.2中似乎已经修复,至少在我刚刚下载的公共测试版中是这样。可以预期,Safari的修复也会及时到来。

iOS 10.1

iOS 10.1: bug present

iOS 10.2(公测版2)

iOS 10.2: bug not present


感谢您编写测试用例。目前我没有iOS设备来检查行为 - 我会在接下来的几天里查看并回复您。然而,它似乎在iOS 10.2 beta中已经修复,这是令人鼓舞的,希望在发布给公众时仍然保持这样的状态。 - ilokhov
1
刚在iOS 10设备上检查了测试用例,并确认了您的发现。您最后的示例包括设置“will-change: transform”(此属性以前我不知道),并在父元素上旋转似乎解决了这个问题。我已经更新了我的原始fiddle,以演示:https://jsfiddle.net/urfbc0gv/由于这提供了解决我的原始问题的方法,因此我将此答案标记为已接受。还要感谢您检查iOS 10.2 beta上的行为-希望这种行为很快就会得到修复。 - ilokhov
1
感谢@ilokhov!will-change CSS属性通常用于手动为可能不会自动检测到的animationtransition启用GPU加速,例如在页面加载后由JS应用的动画。它可以帮助防止元素突然触发硬件加速时可能出现的卡顿。因此,虽然它可能有效,但请注意它也会向浏览器不必要地请求GPU加速。这不是很好看,但仍然是一种解决方法。 - Jacob Ford
如果有人想要贡献或查看,我也将我的演示制作成了一个小的GitHub存储库:https://github.com/unitof/90-degree-safari - Jacob Ford

3

实际上,将旋转变换设置为类似于90.1度的值可以解决这个问题...

我已经测试了很多方法,这里有报告:https://codepen.io/KevinNTH/pen/ZBgKdG

<!-- workaround ios -->
<svg class="wka-ios">
  <g transform="rotate(-90.1 30 30)">
    <circle cx="25" cy="25" r="15"/>
  </g>
</svg>

此外,我没有提供旋转的x和y坐标。transform="rotate(-90.1 55 55)" 对我有帮助。(其中55是SVG视图框宽度的一半) - Prnth

1

我也遇到了这个问题,我暂时采用旋转角度略小于90度的方法来解决它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接