如何应用可在 Chrome 中使用的内联 SVG 蒙版?

Oak*_*Oak 7 html css svg

我想使用在同一 HTML 文件(内联 SVG)中定义的 SVG 形状来剪辑我的元素。

它适用于clip-path:

div {
  width: 200px;
  height: 200px;
  background-color: red;
  clip-path: url("#c");
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <svg>
    <defs>
      <clippath id="c">
        <circle cx="100" cy="100" r="50" />
      </clippath>
    </defs>
  </svg>
</div>
Run Code Online (Sandbox Code Playgroud)

但是,当使用掩码时,虽然这在 Firefox 中工作正常,但在 Chrome 中不应用掩码:

div {
  width: 200px;
  height: 200px;
  background-color: red;
  mask: url("#m");
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <svg>
    <defs>
      <mask id="m">
        <circle cx="100" cy="100" r="50" fill="white" />
      </mask>
    </defs>
  </svg>
</div>
Run Code Online (Sandbox Code Playgroud)

搜索周围(示例),Chrome 似乎并不期望掩码引用定义,而是引用整个图像。如果图像已内联,是否有办法引用整个图像?或者,我还能做些什么来应用内联元素的蒙版吗?

Kai*_*ido 5

这是一个丑陋的js解决方案,它将

  • 抓取你的内容<mask>,
  • 将其复制到新的 svg 元素中(幸运的是 chrome 不需要宽度和高度),
  • 将其转换为 data-URI 并将其设置为-webkit-mask-image属性。

const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
const mask = document.querySelector("mask");
svg.innerHTML = mask.innerHTML;
const markup = new XMLSerializer().serializeToString(svg);
const url = `data:image/svg+xml;charset=utf8,${ encodeURIComponent(markup) }`;
const div = document.getElementById('mask-me');
div.style.webkitMaskImage = `url('${ url }')`;
Run Code Online (Sandbox Code Playgroud)
#mask-me {
  width: 200px;
  height: 200px;
  background-color: red;
  /**
    This will be overidden by -webkit-mask-image even in Firefox.
    We could have avoided it with a CSS variable, e.g
    -webkit-mask-image: var(--workaround-url);
    but Safari acts in all ways as if they did support inline SVG as mask,
    when they don't.
    So, for them, we have to use the workaround everywhere...
  mask-image: url(#m);
  **/
}
Run Code Online (Sandbox Code Playgroud)
<div id="mask-me">
  <svg>
    <defs>
      <mask id="m">
        <circle cx="100" cy="100" r="50" fill="white" />
      </mask>
    </defs>
  </svg>
</div>
Run Code Online (Sandbox Code Playgroud)


对于需要该功能的人mask-mode: luminance,您需要通过以下方式在生成的 SVG 图像中手动执行此操作<feColorMatrix type="luminanceToAlpha"/>:

const svgNS = "http://www.w3.org/2000/svg";
const svg = document.createElementNS(svgNS, "svg");
// create a <filter><feColorMatrix type="luninanceToAllpha"/>
const alpha = document.createElementNS(svgNS, "feColorMatrix");
alpha.setAttribute("type", "luminanceToAlpha");
const filter = document.createElementNS(svgNS, "filter");
filter.setAttribute("id", "alpha");
filter.append(alpha);
svg.append(filter);
// apply the filter on all the <mask> content
const g = document.createElementNS(svgNS, "g");
g.setAttribute("filter", "url(#alpha)");
// luminanceToAlpha disregards semi-transparent pixels,
// so we add a black background to have no such thing 
const bg = document.createElementNS(svgNS, "rect");
bg.setAttribute("width", "100%");
bg.setAttribute("height", "100%");
g.append(bg);

var mask = document.querySelector('mask').cloneNode(true);
g.append(...mask.children);
svg.append(g);

const markup = new XMLSerializer().serializeToString(svg);
const url = "data:image/svg+xml;charset=utf8," + encodeURIComponent(markup);
const div = document.getElementById("mask-me");
div.style.webkitMaskImage = `url('${ url }')`;
Run Code Online (Sandbox Code Playgroud)
.border {
  display: inline-block;
  border: 1px solid;
}
#mask-me {
  width: 300px;
  height: 200px;
  background-color: red;
  /** Safari doesn't really support mask-image using inline SVG either...
    mask-image: url(#m);
    mask-mode: luminance;
  **/
}
Run Code Online (Sandbox Code Playgroud)
<div id="mask-me">
  <svg width="0">
    <defs>
      <mask id="m">
        <circle cx="100" cy="100" r="50" fill="white" />
        <rect x="90" y="90" width="20" height="20" fill="black" />
      </mask>
    </defs>
  </svg>
</div>
Run Code Online (Sandbox Code Playgroud)