Reputation: 2787
I have the following animation with svg
, but they handled completely different on safari and chrome.
let time;
document.querySelector('text').addEventListener('animationstart', () => time = performance.now())
document.querySelector('text').addEventListener('animationend', () => console.log(performance.now() - time))
svg {
width: 100vw;
height: 50vh;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
fill: black;
}
}
text {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: draw 5s forwards;
font-style: italic;
}
<svg>
<text fill='none' x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="5.5" font-size="110">Example</text>
</svg>
On safari, the animation will finish animating the stroke-dashoffset:0
almost close to the JS event print the finished ( 5s which I set), but on chrome, the animation will finish much faster (about 3 or 2 s).
It will wait for several seconds for the animationend
event to fire.
Also, the fill
property on safari will not work at all.
What looks like in safari (with no fill
black):
My questions:
Why the two broswers handle animation differently and why the fill
doesn't work as expected in Safari?
What am I missing?
Upvotes: 3
Views: 116
Reputation: 136638
For the fill
issue, Safari will simply refuse to animate from none
, while other browsers will use a discrete animation, as required by the specs. This will switch from none
to black
directly, at the middle of the animation time.
If you want a smooth transition then begin with a fill
value of transparent
.
setTimeout(() => {
console.log("middle of anim");
}, 2500);
rect {
animation: anim 5s linear forwards;
}
@keyframes anim {
to {
fill: black;
}
}
<svg>
<rect fill="none" width="50" height="50" />
<rect fill="transparent" x="60" width="50" height="50" />
</svg>
For the dashoffset
issue... that's a bit more complex. The value 1000
seems to correspond to Safari's computed path-length for this text, while other browsers have it closer to 500
.
let time;
document.querySelector('text').addEventListener('animationstart', () => time = performance.now())
document.querySelector('text').addEventListener('animationend', () => console.log(performance.now() - time))
svg {
width: 100vw;
height: 50vh;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
fill: black;
}
}
text {
stroke-dasharray: 500; /* will draw half of the stroke in Safari */
stroke-dashoffset: 500;
animation: draw 5s forwards;
font-style: italic;
}
<svg>
<text fill="transparent" x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="5.5" font-size="110">Example</text>
</svg>
The proper solution for this case would be to compute the text's path length, but there is still no API that allows to do that. So the best in your case is to either convert your text to actual path data before-hand, either to use a web-font, analyze it through a library like opentype.js, and get the text info from there, though I didn't test this solution to see if Safari would match the library's results... so if you can, go with the <path>
solution.
Upvotes: 1