svgsafaricss-animationswebkit

Workaround for Safari's lack of support for negative values in SVGs


I'm currently diving into animated SVGs using CSS, and I'm getting ready to say "screw Safari" and just upload a static svg for those users. However, thought I put it to the World before I give up.

Neither element will "flip" when viewed in Safari, but works fine in FF and Chrome. I'm aware that safari doesn't like negative values, but I can't wrap my head around how to revise this code using absolute coordinates instead of relative. Please help!

<?xml version="1.1" encoding="UTF-8"?>
<svg id="logo-layers" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 41 21">
    <defs>
    <style>
    .cls-1 {
                stroke: #4e2164;
        stroke-linecap: round;
        stroke-dasharray: 63;
        animation-name: o-ani;
        animation-duration: 3s;
        animation-timing-function: linear;
        animation-fill-mode: forwards;
      }
.cls-1, .cls-2 {
                fill: none;
                stroke-miterlimit: 10;
      }
.cls-2 {
                stroke: #CCCC00;
        stroke-linecap: round;
        stroke-dasharray: 47;
        animation-name: j-ani;
        animation-duration: 3s;
        animation-timing-function: linear;
        animation-fill-mode: forwards;
      }
@keyframes o-ani {
            0%{
                stroke-dashoffset: 63;
            }
            20%{
                stroke-dashoffset: 0;
            }
            21%{
                d: path("M10.5,0.5c5.523,0,10,4.477,10,10s-4.477,10-10,10s-10-4.477-10-10S4.977,0.5,10.5,0.5z");
            }
            41%{
                d: path("M30.5,0.5c-5.523,0-10,4.477-10,10s4.477,10,10,10s10-4.477,10-10S36.023,0.5,30.5,0.5z");
            }
            100%{
                d: path("M30.5,0.5c-5.523,0-10,4.477-10,10s4.477,10,10,10s10-4.477,10-10S36.023,0.5,30.5,0.5z");
            }
        }   
@keyframes j-ani {
            0%{
                opacity: 0;
            }
            40%{
                opacity: 0;
            }
            41%{
                opacity: 100;
            }
            42%{
                stroke-dashoffset: 47;
            }
            62%{
                stroke-dashoffset: 0;
            }
            63%{
                d: path("M30.5,0.5c-5.523,0-10,4.477-10,10s4.477,10,10,10,10-4.477,10-10");
            }
            83%{
                d: path("M10.5,0.5c5.523,0,10,4.477,10,10s-4.477,10-10,10S0.5,16.023,0.5,10.5");
            }
            100%{
                d: path("M10.5,0.5c5.523,0,10,4.477,10,10s-4.477,10-10,10S0.5,16.023,0.5,10.5");
            }
        }
    </style>
  </defs>
<path id="o-letter" class="cls-1" d="M10.5,.5c5.523,0,10,4.477,10,10s-4.477,10-10,10S.5,16.023,.5,10.5,4.977,.5,10.5,.5Z"/>
  <path id="j-letter" class="cls-2" d="M30.5,.5c-5.523,0-10,4.477-10,10s4.477,10,10,10,10-4.477,10-10"/>
</svg>


Solution

  • As commented, you can replace the d path animation with a simple scale() transformation to flip/mirror the paths at certain keyframes:

    <svg id="logo-layers" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 41 21">
      <defs>
        <style>
          .cls-1 {
            stroke: #4e2164;
            stroke-linecap: round;
            stroke-dasharray: 63;
            animation-name: o-ani;
            animation-duration: 3s;
            animation-timing-function: linear;
            animation-fill-mode: forwards;
          }
    
          .cls-1,
          .cls-2 {
            fill: none;
            stroke-miterlimit: 10;
            transform-origin: center;
          }
    
          .cls-2 {
            stroke: #cccc00;
            stroke-linecap: round;
            stroke-dasharray: 47;
            animation-name: j-ani;
            animation-duration: 3s;
            animation-timing-function: linear;
            animation-fill-mode: forwards;
          }
    
          @keyframes o-ani {
            0% {
              stroke-dashoffset: 63;
            }
    
            20% {
              stroke-dashoffset: 0;
            }
    
            21% {
              transform: scale(1, 1);
            }
    
            41%,
            100% {
              transform: scale(-1, 1);
            }
          }
    
          @keyframes j-ani {
            0% {
              opacity: 0;
            }
    
            40% {
              opacity: 0;
            }
    
            41% {
              opacity: 100;
            }
    
            42% {
              stroke-dashoffset: 47;
            }
    
            62% {
              stroke-dashoffset: 0;
            }
    
            63% {
              transform: scale(1, 1);
            }
    
            83%,
            100% {
              transform: scale(-1, 1);
            }
          }
        </style>
      </defs>
      <path id="o-letter" class="cls-1" d="M10.5,.5c5.523,0,10,4.477,10,10s-4.477,10-10,10S.5,16.023,.5,10.5,4.977,.5,10.5,.5Z" />
      <path id="j-letter" class="cls-2" d="M30.5,.5c-5.523,0-10,4.477-10,10s4.477,10,10,10,10-4.477,10-10" />
    </svg>

    It's crucial to define a transform-origin: center (or define the center coordinates explicitely like transform-origin: 20.5px 10.5px) otherwise the browser assumes. We can replace the d transformation since both states don't really change the path geometry.

    Unfortunately, safari/webkit still doesn't support d animations/transitions while other engines support it flawlessly for may years. See caniuse stats.

    Worth noting, SMIL animations are supported by all browsers but you may find a lot of comments in older SO posts they are removed from Chromium. Fortunately, Chromium changed their mind.