Search code examples
firefoxanimationsvgmask

animated svg mask doesn't work in firefox


h1 everyone, i'm trying to make a cross-browser animation based on svg mask for svg elements. At first, I caught a bug with css, in firefox mask doesn't work with css 'width' and 'height', only with inline properties. So, next question - how to animate mask for firefox, nothing harder that 'width resize'. https://codepen.io/flyby/pen/KmYOgb

<div id='cont'>
  <svg>
    <defs>
      <mask id='rectMask' maskUnits='userSpaceOnUse' maskContentUnits='userSpaceOnUse' transform='scale(1)'>
        <rect x='0' y='0' id='maskRect' width='700' height='850'/>
      </mask>
    </defs>
    <path id='maskedPath' d='m 0,0 l 650,0 -100,850 -550,0 z' mask='url(#rectMask)'/>
    <path id='riverPath' d='m 653,0 l -100,850' mask='url(#rectMask)'/>
    <path id='notMaskedPath' d='m 655,0 l 650,0 0,850 -750,0 z'/>
  </svg>
</div>

CSS:

body {
  margin:0;
  padding:0;
  overflow:hidden;
}
#cont {
  width:100vw;
  height:100vh;
  background-color:rgb(50,50,50);
}
svg {
  width:100%;
  height:100%;
}
#maskedPath {
  stroke:none;
  fill:rgb(230,230,230);
}
#notMaskedPath {
  stroke:none;
  fill:rgb(230,230,230);
}
#riverPath {
  stroke:rgb(50,160,240);
  stroke-width:8;
  fill:none;
}
#maskRect {
  width:0px;
  height:850px;
  fill:white;
  stroke:none;
  animation: resize 3s linear infinite;
}
@-moz-keyframes resize {
  50% {width: 700px !important;}
  0%,100% {width: 0px !important;}
}

Solution

  • Like you have discovered, your can't (yet) set geometric properties, like width and height of SVG elements in Firefox. It's not a bug. It's just an SVG 2 thing that Firefox has not implemented yet, but Chrome has.

    The solution is to use the built-in SVG ("SMIL") animation elements, instead of CSS animation.

    body {
      margin:0;
      padding:0;
      overflow:hidden;
    }
    #cont {
      width:100vw;
      height:100vh;
      background-color:rgb(50,50,50);
    }
    svg {
      width:100%;
      height:100%;
    }
    #maskedPath {
      stroke:none;
      fill:rgb(230,230,230);
    }
    #notMaskedPath {
      stroke:none;
      fill:rgb(230,230,230);
    }
    #riverPath {
      stroke:rgb(50,160,240);
      stroke-width:8;
      fill:none;
    }
    #maskRect {
      fill:white;
      stroke:none;
    }
    <!--this animation doesn't work in FIREFOX, and not tested in IE11 ad Edge YET, WILL BE FIXED SOON (I HOPE)-->
    <div id='cont'>
      <svg>
        <defs>
          <mask id='rectMask' maskUnits='userSpaceOnUse' maskContentUnits='userSpaceOnUse' transform='scale(1)'>
            <rect x='0' y='0' width="0" height="850" id='maskRect'>
              <animate attributeName="width"
                       keyTimes="0; 0.4; 0.5; 1"
                       values="0; 670; 670; 0"
                       dur="4s" repeatCount="indefinite"/>
            </rect>
          </mask>
        </defs>
        <path id='maskedPath' d='m 0,0 l 650,0 -100,850 -550,0 z' mask='url(#rectMask)'/>
        <path id='riverPath' d='m 653,0 l -100,850' mask='url(#rectMask)'/>
        <path id='notMaskedPath' d='m 655,0 l 650,0 0,850 -750,0 z'/>
      </svg>
    </div>