CSS SVG 蒙版上的过渡?

CSS transition on the mask of an SVG?

我在一个内联 SVG 中有一个图像,当它悬停在上面时会在两个蒙版之间切换。

但是,CSS 转换不适用于 transition-property: mask;

是否有其他方法可用于 CSS 转换?

我也试过设置样式 <mask> 但似乎无法设置定义元素的样式 (?)。

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
</head>
<body>
<div style="width: 604px; height: 302px; margin: 20px auto;"> <!-- IE needs width AND height specified to scale the SVG inside correctly. -->
<svg id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1208 604">

 <style type="text/css">
  /* <![CDATA[ */
  .mask_hover a:link,
  .mask_hover a:visited {
   mask: url(#mask_right);
  }
  .mask_hover a:hover,
  .mask_hover a:active {
   transition-property: mask;
   transition-duration: 0.4s;
   transition-timing-function: ease-in-out;
   mask: url(#mask_left);
  }
  /* ]]> */
 </style>

 <defs>
  <mask id="mask_left">
   <circle id="circle_l" cx="416" cy="216" r="202" fill="#fff"/>
  </mask>
  
  <mask id="mask_right">
   <circle id="circle_r" cx="809" cy="337" r="202" fill="#fff"/>
  </mask>
  
 </defs>
 
 <g class="mask_hover">
  <a xlink:href="#">
   <image id="img" width="1208" height="604" xlink:href="https://i.stack.imgur.com/LCpGU.jpg"/>
  </a>
 </g>
</svg>
</div>
</body>
</html>

图片来源:Pixabay

真的不是mask属性不能动画,而是url().

要创建过渡,您需要有一个状态 1 到状态 2,并且可以在两个状态之间创建插值。
当您使用 url(#1) 并希望转到 url(#2) 时,无法在这两个状态之间创建任何插值,因为 url(#1.5) 不会是中间状态。

不过可以动画化的是蒙版的内容。

在 SVG2 中,您可以直接设置从 CSS 更改的属性(即 cxcy),但这仍然仅受 Blink&Safari 浏览器支持:

<svg id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1208 604">
  <style type="text/css">
  /* <![CDATA[ */
    .mask_hover a:link,
    .mask_hover a:visited {
      mask: url(#mask);
    }
    #mask > circle {
      transition-property: cx, cy;
      transition-duration: 0.4s;
      transition-timing-function: ease-in-out;    
    }
    .mask_hover a:hover + defs #mask > circle,
    .mask_hover a:active + defs #mask > circle {
      cx: 416;
      cy: 216;
    }
  /* ]]> */
  </style>
  <g class="mask_hover">
    <a xlink:href="#">
      <image id="img" width="1208" height="604" xlink:href="https://i.stack.imgur.com/LCpGU.jpg"/>
    </a>
    <!-- we need to move it here so we can target it with our CSS rules -->
    <defs>
      <mask id="mask">
        <circle id="circle_l" cx="809" cy="337" r="202"   fill="#fff"/>
      </mask>  
    </defs>
  </g>
</svg>

对于不支持这部分 SVG2 的其他浏览器,您应该可以使用转换 属性 来完成它,但不知何故,Firefox 不接受它...

<svg id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1208 604">
  <style type="text/css">
  /* <![CDATA[ */
    .mask_hover a:link,
    .mask_hover a:visited {
    mask: url(#mask);
    }
    #mask > circle {
    transition-property: transform;
    transition-duration: 0.4s;
    transition-timing-function: ease-in-out;    
    }
    .mask_hover a:hover + defs #mask > circle,
    .mask_hover a:active + defs #mask > circle {
    transform: translate(-393px, -121px);
    }
  /* ]]> */
  </style>
  <g class="mask_hover">
    <a xlink:href="#">
     <image id="img" width="1208" height="604" xlink:href="https://i.stack.imgur.com/LCpGU.jpg"/>
    </a>
  <!-- we need to move it here so we can target it with our CSS rules -->
  <defs>
    <mask id="mask">
     <circle id="circle_l" cx="809" cy="337" r="202" fill="#fff"/>
    </mask>  
  </defs>
  </g>
</svg>

所以您可能还想尝试使用 SMIL,但是您将无法使用 :active 规则,而且 Safari 在实现悬停状态时存在错误...

<svg id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1208 604">
  <style type="text/css">
  /* <![CDATA[ */
    .mask_hover a:link,
    .mask_hover a:visited {
      mask: url(#mask);
    }
  /* ]]> */
  </style>
  <defs>
    <mask id="mask">
      <circle id="circle_r" cx="809" cy="337" r="202" fill="#fff">
        <animateTransform attributeName="transform"
          attributeType="XML"
          type="translate"
          to="-393 -121"
          dur="0.4s"
          fill="freeze"
          begin="anchor.mouseover"/>
        <animateTransform attributeName="transform"
          attributeType="XML"
          type="translate"
          to="0 0"
          dur="0.4s"
          fill="freeze"
          begin="anchor.mouseout"/>
      </circle>
   </mask>
  </defs>
  <g class="mask_hover">
    <a xlink:href="#" id="anchor">
      <image id="img" width="1208" height="604" xlink:href="https://i.stack.imgur.com/LCpGU.jpg"/>
    </a>
  </g>
</svg>

所以最终的方法可能是仅使用来自 CSS:

clip-path 来实现整个事情

<svg id="artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1208 604">
  <style type="text/css">
  /* <![CDATA[ */
    .mask_hover a image {
      transition: clip-path .4s;
    }
    .mask_hover a {
      pointer-events: all;
    }
    .mask_hover a:link image,
     .mask_hover a:visited image{
      clip-path: circle(202px at 809px 337px);
    }
    .mask_hover a:hover image,
     .mask_hover a:active image{
      clip-path: circle(202px at 416px 216px);
    }
  /* ]]> */
  </style>
  <g class="mask_hover">
    <a xlink:href="#">
      <image id="img" width="1208" height="604" xlink:href="https://i.stack.imgur.com/LCpGU.jpg"/>
      <!-- so we can hover everywhre -->
      <rect fill="none" width="1208" height="604"/>
    </a>
  </g>
</svg>