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 rotat
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: the bug's presence is affected by the current zoom level.
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;
}
In Safari 10.0.1 and iOS 10.1, strange behavior can be observed on SVG shapes with rotate
values not divisible by 90 degrees, when transform-origin: center center;
transform: rotate(-90deg);
The stroke improperly begins at 3:00, as if the transform
rule hadn't been applied.
transform: rotate(-90.1deg);
The stroke begins at (twelve seconds before) 12:00, as expected.
transform: rotate(-0.25turn);
The same bug applies to any rotate
value which computes to a multiple of 90 degrees.
transform: rotate(-0.251turn);
43 seconds before noon.
But when the SVG element specifies a viewBox
which is being scaled down, things can get weird:
transform: rotate(-90deg);
So far, so the same.
transform: rotate(-90.1deg);
But now, offsetting by a little bit doesn't work, unless you zoom in the page in past a certain zoom threshold (either via pinching, or View > Zoom
and/or keyboard shortcut). Try it; it's unsetting!
This is probably because of some rounding of that the zooming engine performs, because...
transform: rotate(-92deg);
offsetting by a larger amount restores expected behavior.
If the SVG element is not being scaled down, behavior identical to the first section resumes. Zooming has no effect:
transform: rotate(-90deg);
Top: No scaling (viewBox dimensions match parent element's)
Bottom: Scaling up (viewBox dimensions half of parent element's)
transform: rotate(-90.1deg);
Top: No scaling (viewBox dimensions match parent element's)
Bottom: Scaling up (viewBox dimensions half of parent element's)
But there is one exception:
On the parent svg
element:
transform: rotate(-90deg);
will-change: transform;
Iff the the the rotation is applied to a parent of the SVG shape (including the SVG element itself) along with the rule will-change: transform
, all rotation values work as expected.
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.
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.