Tengo la siguiente animación con svg
, pero se manejaron de manera completamente diferente en Safari y 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>
En safari, la animación terminará de animar el stroke-dashoffset:0
casi cerca del evento JS, imprima el acabado (5 s que configuré), pero en Chrome, la animación terminará mucho más rápido (alrededor de 3 o 2 s). Esperará varios segundos hasta que se active el evento animationend
.
Además, la propiedad de fill
en safari no funcionará en absoluto.
Lo que parece en safari (sin fill
negro):
Mis preguntas:
¿Por qué los dos navegadores manejan la animación de manera diferente y por qué el fill
no funciona como se esperaba en Safari?
¿Qué me estoy perdiendo?
Para el problema de fill
, Safari simplemente se negará a animar desde none
, mientras que otros navegadores utilizarán una animación discreta, según lo requieran las especificaciones. Esto cambiará de none
a black
directamente, en medio del tiempo de animación.
Si desea una transición suave, comience con un valor de fill
de 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>
Para el tema de dashoffset
... eso es un poco más complejo. El valor 1000
parece corresponder a la longitud de la ruta calculada por Safari para este texto, mientras que otros navegadores lo tienen más cerca de 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>
La solución adecuada para este caso sería calcular la longitud de la ruta del texto, pero aún no existe una API que permita hacerlo . Entonces, lo mejor en su caso es convertir su texto en datos de ruta reales de antemano, ya sea para usar una fuente web, analizarla a través de una biblioteca como opentype.js y obtener la información de texto de allí, aunque no lo hice. Pruebe esta solución para ver si Safari coincidiría con los resultados de la biblioteca... así que, si puede, elija la solución <path>
.