SVG transform rotate by 90, 180 or 270 degrees not working on circle in Safari iOS 10

房东的猫 提交于 2019-12-04 16:12:27

问题


I want to create a donut chart using an SVG circle element by setting stroke-dasharray and varying stroke-dashoffset. The SVG element needs to be rotated by 270 (or -90) degrees in order for the chart "bar" to start at the top. Here is the code:

http://jsfiddle.net/q3wb6gkq/

The rotation angle is specified using the first number in transform="rotate(270, 80, 80)".

The problem is: when viewed in Safari on iOS 10 this rotation is not applied. In fact, setting 90, 180 or 270 degree rotation has no effect. The same angles but negative (for example -90) are also not applied.

Here is a screenshot of the above fiddle in Safari on iOS 10.0.1:

And here is the same fiddle in Safari on iOS 9.3.5:

As a workaround, I have found that using something like 270.1 degrees solves the problem, however I would like to know why 270 is not working and if there is a better way of dealing with it.


回答1:


I've experienced this painfully on iOS 10.1 and Safari 10.0.1. The bug is definitely triggered by any rotate value which computes to a value divisible by 90 degrees.

But it gets weirder.

See this demo/series of minimal test cases I put together (jsFiddle version here). Best to run the snippet then expand to full page:

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>

As stated in the demo, it appears to be fixed in iOS 10.2, at least in the public beta version I just downloaded. Presumably, a Safari fix will also be arriving in due time.

iOS 10.1

iOS 10.2 (Public Beta 2)




回答2:


Indeed, set the rotate transformation to something like 90.1deg solves the issue...

I have test many things, reported here: 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>



回答3:


This is happening to me as well, I settled on using a rotation just shy of being divisible by 90 degrees to get around this in the interim.



来源:https://stackoverflow.com/questions/40363916/svg-transform-rotate-by-90-180-or-270-degrees-not-working-on-circle-in-safari-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!