svg mask 在 chrome 中不起作用,但在 FF 中有效

svg mask does not work in chrome but works in FF

提问人:Rodolfo Awenydd Luna Bernal 提问时间:10/27/2023 更新时间:10/31/2023 访问量:49

问:

我在这里没有想法,我制作了一个动画 svg 来使用 javascript 屏蔽图像,非常简单,但它在 chrome 和 edge 中不起作用,但在 firefox 中它工作正常,控制台没有任何错误,我阅读了文档,从技术上讲它应该可以工作。我的主要目标是移动设备,所以这必须在 chrome :( 上工作这是 html 和脚本的结构:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
    <link rel="stylesheet" href="css/styles.css">
</head>

<body>
    <div class="main">
        <div id="logo"><img src="imgs/realestate_logo.svg" alt="" /></div>
        <div class="combo">
            <svg width="100%" height="100%" viewBox="0 0 400 300">
                <defs>
                    <mask id="mask">
                        <rect fill="#000000" x="0" y="0" width="400" height="300"></rect>
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                        <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
                    </mask>
                </defs>
            </svg>
            <div class="container">
                <img src="imgs/villa.webp" alt="Your Image">
            </div>
        </div>
        <hr />
        <div class="texto">
            <p>Soy el texto</p>
        </div>
    </div>
    <script>
        window.addEventListener('load', function() {

            // Logo Animation
            const logoElement = document.getElementById("logo");
            setTimeout(() => {
                logoElement.style.opacity = "1";
                logoElement.style.transform = "translateY(0)";
            }, 500);  // Delay for half a second before starting the logo animation

            const img = document.querySelector(".container img");
            const circles = document.querySelectorAll("#mask circle");

            // Image dimensions and circle animation
            const width = img.naturalWidth;
            const height = img.naturalHeight;
            const aspectRatio = (height / width) * 100;
            const comboElement = document.querySelector(".combo");
            comboElement.style.paddingBottom = `${aspectRatio}%`;
            animateCurrentCircle(0);

            // Add event listener for window resize
            window.addEventListener('resize', function () {
                animateCurrentCircle(0);  // Reset the circle animation upon resizing
            });

            function getRandom(min, max) {
                return Math.floor(Math.random() * (max - min + 1) + min);
            }

            function animateCurrentCircle(index) {
                if (index >= circles.length) {
                    index = 0;
                }

                const svgWidth = parseFloat(getComputedStyle(document.querySelector("svg")).width);
                const svgHeight = parseFloat(getComputedStyle(document.querySelector("svg")).height);

                let maxi = Math.min(svgWidth, svgHeight) / 2;
                const r = getRandom(maxi / 4, maxi);
                const maxCx = svgWidth - r;
                const minCx = r;
                const maxCy = svgHeight - r;
                const minCy = r;
                const cx = getRandom(minCx, maxCx);
                const cy = getRandom(minCy, maxCy);

                const circle = circles[index];
                circle.setAttribute("r", r);
                circle.setAttribute("cx", cx);
                circle.setAttribute("cy", cy);

                setTimeout(() => {
                    animateCurrentCircle(index + 1);
                }, 400);
            }
        });
    </script>
</body>

</html>

这是 css:

@font-face {
    font-family: 'Addington';
    src: url('../fonts/AddingtonCF-Light.ttf') format('truetype');
}

body, html {
    height: 100%; 
    margin: 0;   
    padding: 0;  
    background-color: #f4f4f4;
    font-family: 'Addington', serif; 
}

.main {
    display: flex;
    flex-direction: column; 
    align-items: center;   
    justify-content: space-evenly;
    height: 100%;         
    max-width: 1200px;     
    margin: 0 auto;        
    padding: 0px;          
    background-color: #fff; 
    gap: 10px;
}

#logo img {
    width: 90%;            
    min-width: 300px;      
    max-width: 400px;       
    height: auto;          
    display: block;        
    margin: 0 auto;        
}

#logo, .combo {
    width: 100%;          
    position: relative;    
}

.combo {
    width: 90%;            
    max-width: 720px;      
    min-width: 300px;     
    margin: 0 auto;        
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: auto;
}

.container {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;          
    height: 100%;         
}

.container img {
    width: 100%;          
    display: block;        
    object-fit: cover;
    /*-webkit-mask-image: url(#mask);*/
    -webkit-mask-size: cover;
    -webkit-mask-repeat: no-repeat; /* Added to ensure mask doesn't repeat */
    /*mask-image: url(#mask);*/
    mask-size: cover;
    mask-repeat: no-repeat; /* Added to ensure mask doesn't repeat */
    height: 100%;
    -webkit-mask: url(#mask);
    mask: url(#mask);
}

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

circle {
    transition: all 5s ease;
}

.texto {
    font-size: 18px;
}

#logo {
    opacity: 0;
    transform: translateY(-50px);
    transition: opacity 1s, transform 1s;
}

任何帮助将不胜感激,谢谢!!

SVG 跨浏览器 掩码

评论

1赞 Robert Longson 10/27/2023
如果您认为自己发现了 Chrome 错误,请将其报告给 Chrome 的错误跟踪器 - 除非您已经在那里找到了它。

答:

0赞 herrstrietzel 10/31/2023 #1

Firefox 是目前唯一支持应用于 HTML 元素的引用 svg 掩码的浏览器引擎。因此,您的面具在苹果移动设备(safari/webkit)上不起作用。参见 “css-tricks: Clipping and Masking in CSS”

作为解决方法,您可以将元素替换为内联 svg 元素。<img><image>

<div class="container">
  <svg width="100%" height="100%">
    <description>Your Image</description>
    <image class="masked" href="https://picsum.photos/id/237/200/300" width="100%" height="100%" preserveAspectRatio="xMidYMid slice" />
  </svg>
</div> 

preserveAspectRatio="xMidYMid slice"缩放和拟合类似于 CSS 的图像object-fit:cover

window.addEventListener("load", function() {
  // Logo Animation
  const logoElement = document.getElementById("logo");
  setTimeout(() => {
    logoElement.style.opacity = "1";
    logoElement.style.transform = "translateY(0)";
  }, 500); // Delay for half a second before starting the logo animation

  //const img = document.querySelector(".container img");
  const img = document.querySelector(".container image");
  const circles = document.querySelectorAll("#mask circle");

  const {
    width,
    height
  } = img.getBBox();

  // Image dimensions and circle animation
  const imgParentSvg = img.closest("svg");
  imgParentSvg.setAttribute("viewBox", `0 0 ${width} ${height}`);

  animateCurrentCircle(0);

  // Add event listener for window resize
  window.addEventListener("resize", function() {
    animateCurrentCircle(0); // Reset the circle animation upon resizing
  });

  function getRandom(min, max) {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }

  function animateCurrentCircle(index) {
    if (index >= circles.length) {
      index = 0;
    }

    const svgWidth = parseFloat(
      getComputedStyle(document.querySelector("svg")).width
    );
    const svgHeight = parseFloat(
      getComputedStyle(document.querySelector("svg")).height
    );

    let maxi = Math.min(svgWidth, svgHeight) / 2;
    const r = getRandom(maxi / 4, maxi);
    const maxCx = svgWidth - r;
    const minCx = r;
    const maxCy = svgHeight - r;
    const minCy = r;
    const cx = getRandom(minCx, maxCx);
    const cy = getRandom(minCy, maxCy);

    const circle = circles[index];
    circle.setAttribute("r", r);
    circle.setAttribute("cx", cx);
    circle.setAttribute("cy", cy);

    setTimeout(() => {
      animateCurrentCircle(index + 1);
    }, 400);
  }
});
body,
html {
  height: 100%;
  margin: 0;
  padding: 0;
  background-color: #f4f4f4;
  font-family: 'Addington', serif;
}

.main {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-evenly;
  height: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0px;
  background-color: #fff;
  gap: 10px;
}

#logo img {
  width: 90%;
  min-width: 300px;
  max-width: 400px;
  height: auto;
  display: block;
  margin: 0 auto;
}

#logo,
.combo {
  width: 100%;
  position: relative;
}

.combo {
  width: 90%;
  max-width: 720px;
  min-width: 300px;
  margin: 0 auto;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: auto;
}

.container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.container image {
  width: 100%;
  display: block;
  height: 100%;
  -webkit-mask: url(#mask);
  mask: url(#mask);
}

svg {
  border: 1px solid #ccc
}

circle {
  transition: all 5s ease;
}

.texto {
  font-size: 18px;
}

#logo {
  opacity: 0;
  transform: translateY(-50px);
  transition: opacity 1s, transform 1s;
}
<div class="main">
  <div id="logo"><img src="https://picsum.photos/id/230/100/100" alt="" /></div>
  <div class="combo">
    <svg width="100%" height="100%" viewBox="0 0 400 300">
      <defs>
        <mask id="mask">
          <rect fill="#000000" x="0" y="0" width="400" height="300"></rect>
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
          <circle fill="#FFFFFF" cx="200" cy="150" r="0" />
        </mask>
      </defs>
    </svg>
    <div class="container">
      <svg width="100%" height="100%">
        <description>Your Image</description>
        <image class="masked" href="https://picsum.photos/id/237/200/300" width="100%" height="100%" preserveAspectRatio="xMidYMid slice" />
      </svg>
    </div>
  </div>
  <hr />
  <div class="texto">
    <p>Soy el texto</p>
  </div>
</div>