繁体   English   中英

不正确 SVG 掩码 Position 使用相对位置时加载(Chrome)

[英]Incorrect SVG Mask Position On Load When Using Relative Positions (Chrome)

我正在做一个项目,我想在其中显示图像(模糊)并将“放大镜”(带有非模糊图像的圆圈)放在感兴趣的位置,用户可以与之交互: 在此处输入图像描述

因此,图像与 svg 元素一起放置在包装器中。 该图像应驱动 svg 的大小,因此我没有使用view-box属性。 SVG 绝对定位并覆盖整个包装器。 现在我可以使用相对定位在 svg 上放置元素。 然后我在 position 处放置一个圆圈,我希望放大镜成为(仍然工作正常)。 作为蒙版,我在相同的 position(在蒙版元素内)创建了另一个圆圈,并在未模糊的图像上使用了 css蒙版(#id)

这在 Firefox 上运行良好,但在 Chrome 上不会显示掩码。

在此处输入图像描述

只是,当我调整 window 的大小时,遮罩出现并且一切正常。

似乎掩码元素未正确计算到其父元素。 面具放在左上角。 调整 window 的大小可修复此行为。

HTML

<div class="container">
  <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200">
  <!-- SVG (purple) -->
  <!-- Setting a viewbox can solve the Issue, but I would prefer  not to. -->
  <div class="wrapper">
    <svg>
      <!-- Define the Mask -->
      <defs>

      </defs>

      <mask id="mask">
        <circle r="20%" cx="43%" cy="20%" fill="white"></circle>
      </mask>

      <!-- The stroke of the masked cicle. -->
      <circle r="20%" cx="43%" cy="20%" stroke="white" fill="transparent"></circle>

      <!-- The Element we want to mask. -->
      <image href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image>
    </svg>
  </div>
</div>

CSS

img {
  filter: blur(4px);
}

image {
  mask: url(#mask);
}


svg {
  position: absolute;
  left:0;
  top:0;
  width:100%;
  height:100%;

如何在启动时修复 chrome 的这种行为? 或者是否有解决方法,例如手动触发遮罩层的重新计算?

我在这里创建了一个工作示例: https://codepen.io/Ukmasmu/pen/NWNrGoW

任何帮助将不胜感激:提前致谢:)

我认为问题来自 Chrome 的渲染引擎无法正确推断自动调整大小的视图框的尺寸。 如果您检查<mask>元素中的<circle>元素和 hover 元素,您会发现它计算的尺寸不正确,而在其他浏览器中它解析为正确的像素值。

更简单的方法是在加载<img>元素时简单地使用 JS 手动设置viewBox属性,以强制 Chrome 根据显式 viewbox 值正确地重新呈现 SVG。

 const img = document.querySelector('img'); const svg = document.querySelector('svg'); img.addEventListener('load', (e) => { svg.setAttribute('viewBox', `0 0 ${img.clientWidth} ${img.clientHeight}`) });
 img { filter: blur(4px); } image { mask: url(#mask); } svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(138, 43, 226, 0.2); }.container { background-color: gray; position: relative; } html, body { width: 100%; height: 100%; margin: 0; } body { background-color: #111; display: flex; justify-content: center; align-items: center; }
 <div class="container"> <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200"> <,-- SVG (purple) --> <.-- Setting a viewbox can solve the Issue. but I would prefer not to. --> <div class="wrapper"> <svg> <:-- Define the Mask --> <defs> </defs> <mask id="mask"> <circle r="20%" cx="43%" cy="20%" fill="white"></circle> </mask> <.-- The stroke of the masked cicle. --> <circle r="20%" cx="43%" cy="20%" stroke="white" fill="transparent"></circle> <!-- The Element we want to mask. --> <image href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image> </svg> </div> </div>

这绝对是一个错误,可能是bug=330815

强制重新绘制蒙版将解决此问题。

这可以通过在页面加载时进行简单的 class 设置来实现,该设置将强制displayposition更改:

 onload = evt => document.body.classList.add('loaded');
 /* Chrome hack around bug 330815 */.loaded mask { display: block; } img { filter: blur(4px); } image { mask: url("#mask"); } svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(138, 43, 226, 0.2); }.container { background-color: gray; position: relative; } html, body { width: 100%; height: 100%; margin: 0; } body { background-color: #111; display: flex; justify-content: center; align-items: center; }
 <div class="container"> <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200"> <,-- SVG (purple) --> <.-- Setting a viewbox can solve the Issue. but I would prefer not to. --> <div class="wrapper"> <svg> <:-- Define the Mask --> <defs> <mask id="mask"> <circle r="20%" cx="43%" cy="20%" fill="white"/> </mask> </defs> <.-- The stroke of the masked cicle. --> <circle r="20%" cx="43%" cy="20%" stroke="white" fill="none"/> <!-- The Element we want to mask. --> <image mask="url(#mask)" href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image> </svg> </div> </div>

如果你真的想要没有 JS 的东西,你也可以通过 SMIL 实现同样的破解。
例如,在<mask>中为<use>href值设置动画似乎可以做到这一点:

 img { filter: blur(4px); } image { mask: url("#mask"); } svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(138, 43, 226, 0.2); }.container { background-color: gray; position: relative; } html, body { width: 100%; height: 100%; margin: 0; } body { background-color: #111; display: flex; justify-content: center; align-items: center; }
 <div class="container"> <img src="https://source.unsplash.com/2Ts5HnA67k8/400x200"> <,-- SVG (purple) --> <.-- Setting a viewbox can solve the Issue. but I would prefer not to. --> <div class="wrapper"> <svg> <:-- Define the Mask --> <defs> <circle r="20%" cx="43%" cy="20%" id="circle"/> <mask id="mask"> <use x="0" href="#circle" fill="white"> <.-- Chrome hack around bug 330815 --> <animate attributeName="href" to="#circle" begin="0" dur="0s"/> </use> </mask> </defs> <.-- The stroke of the masked cicle. --> <use href="#circle" fill="transparent" stroke="white"/> <!-- The Element we want to mask. --> <image mask="url(#mask)" href="https://source.unsplash.com/2Ts5HnA67k8/400x200"></image> </svg> </div> </div>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM