【问题标题】:CSS transition on the mask of an SVG?SVG蒙版上的CSS过渡?
【发布时间】:2019-08-06 01:23:23
【问题描述】:

我在内联 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

【问题讨论】:

    标签: css svg css-transitions


    【解决方案1】:

    实际上不能动画的不是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 的其他浏览器,您应该可以使用 transform 属性,但不知何故,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>

    【讨论】:

    • 感谢您提供这个解释清楚的答案!我应该更多地解释我的目标和原因。我想要动画的过渡是淡入/淡出效果。我通过对图像的各种实例的不透明度进行动画处理来做到这一点,每个实例都以不同的方式进行剪辑 (this is the result)。问题是它在处理大量剪切路径(接近 50 个)时性能不佳。您是否认为可以将蒙版的填充颜色从黑色(不可见)变为白色(可见)动画(通过过渡)?
    • 是的, 现在是可动画的,所以理论上这应该可以工作,但是再一次,你可能会在各种实现中遇到很多差异,特别是旧的 IE 可能无法工作。
    • 看到&lt;mask&gt; 必然在&lt;defs&gt; 内部,你知道一种方法来定位它的填充颜色吗?我无法解决。
    • 啊,我明白了。杰出的!不知道这是可能的。我会尝试这种方法。
    猜你喜欢
    • 2021-06-12
    • 1970-01-01
    • 2019-05-12
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 2018-09-23
    • 2017-12-22
    相关资源
    最近更新 更多