剪切路径在图像上有效,但在div上无效

4
在MDN上有一个关于如何在图像上使用剪辑路径SVG的示例。但是,相同的剪辑路径似乎不能应用于
元素。有人能够澄清一下吗?
  • 为什么这段代码无法按预期工作
  • 让SVG剪辑路径在div上起作用的方法

示例代码(基于MDN文档link)对图像进行裁剪

#clipped {
  clip-path: url(#cross);
}
<img id="clipped" src="https://mdn.mozillademos.org/files/12668/MDN.svg"
    alt="MDN logo">
<svg height="0" width="0">
  <defs>
    <clipPath id="cross">
      <rect y="110" x="137" width="90" height="90"/>
      <rect x="0" y="110" width="90" height="90"/>
      <rect x="137" y="0" width="90" height="90"/>
      <rect x="0" y="0" width="90" height="90"/>
    </clipPath>
  </defs>
</svg>

上相同的剪切路径(似乎不起作用)

#clipped {
  width: 100px;
  height: 100px;
  background: black;
  clip-path: url(#cross);
}
<div id="clipped"></div>
<svg height="0" width="0">
  <defs>
    <clipPath id="cross">
      <rect y="110" x="137" width="90" height="90"/>
      <rect x="0" y="110" width="90" height="90"/>
      <rect x="137" y="0" width="90" height="90"/>
      <rect x="0" y="0" width="90" height="90"/>
    </clipPath>
  </defs>
</svg>


该页面下方的“浏览器兼容性”部分列出了“在HTML元素上”的工作方式适用于多个非MS浏览器,但也将其标记为“实验性的。预计未来行为会发生变化。” // https://caniuse.com/#feat=css-clip-path 对不同浏览器中支持级别的详细说明。 - 04FS
@04FS 根据 caniuse 表格,Firefox 70 应该完全支持。但示例在那里也无法工作。关于实验阶段的观点很公正。如果共识是这是一个(部分)未实现/未记录的功能,我会给 MDN 留言。 - Rob Monhemius
Firefox支持使用SVG clipPath剪切div。 - Robert Longson
2
请将 div 的大小更改为 width: 300px; height: 300px; - enxaneta
@enxaneta 很好的发现。似乎像素大小与svg内的一个单位相关:)。如果您发布答案,我可以接受它并关闭问题;)。 - Rob Monhemius
3个回答

3

正如@enxaneta所指出的,这完全是尺寸问题。如果你增加div的尺寸,你就会看到效果:

#clipped {
  width: 300px;
  height: 200px;
  background: black;
  clip-path: url(#cross);
}
<div id="clipped"></div>
<svg height="0" width="0">
  <defs>
    <clipPath id="cross">
      <rect y="110" x="137" width="90" height="90"/>
      <rect x="0" y="110" width="90" height="90"/>
      <rect x="137" y="0" width="90" height="90"/>
      <rect x="0" y="0" width="90" height="90"/>
    </clipPath>
  </defs>
</svg>

或者你可以使用mask来实现动态效果。技巧是将四个白色矩形放在每个角落,并且白色表示可见

.box {
  width: 100px;
  height: 100px;
  margin:5px;
  background: linear-gradient(red,blue);
  -webkit-mask:
    linear-gradient(white,white) top left,
    linear-gradient(white,white) top right,
    linear-gradient(white,white) bottom left,
    linear-gradient(white,white) bottom right;
  -webkit-mask-size:40% 40%;
  -webkit-mask-repeat:no-repeat;
  -mask:
    linear-gradient(white,white) top left,
    linear-gradient(white,white) top right,
    linear-gradient(white,white) bottom left,
    linear-gradient(white,white) bottom right;
  mask-size:40% 40%;
  mask-repeat:no-repeat;
}
<div class="box"></div>

<div class="box" style="width:200px;height:200px;"></div>


3
解决您的问题的方法是使用clipPathUnits="objectBoundingBox",并根据0到1之间的大小构建剪切路径,如下所示:

#clipped {
  margin:1em;
  width: 100px;
  height: 100px;
  background: black;
  display:inline-block;
  clip-path: url(#cross);
}
#clipped.big{
  width: 200px;
  height: 200px;
}
<div id="clipped"></div>
<div id="clipped" class="big"></div>
<svg viewBox="0 0 1 1">
  
    <clipPath id="cross" clipPathUnits="objectBoundingBox">
       <rect y="0" x="0" width=".4" height=".4"/>
       <rect y="0.6" x="0" width=".4" height=".4"/>
       <rect y="0" x="0.6" width=".4" height=".4"/>
       <rect y="0.6" x="0.6" width=".4" height=".4"/>
    </clipPath>
  
</svg>


1
相反的效果呢?有没有办法应用一个“神奇”的属性来隐藏交叉部分并显示其他部分,同时保持剪辑路径像这个一样简单? - Temani Afif
1
我想我们必须定义4个矩形:https://jsfiddle.net/umd5vLn2/? - Temani Afif
好的,你可以两者都保留。我只是想知道是否有一种方法可以保持相同并能够拥有相反的效果(就像使用遮罩时我们可以反转白色和透明)。 - Temani Afif
1
这个回答和Temani Afif的回答似乎都是正确的。如果您使用具有相同高宽比的图像,则“objectBoundingBox”解决方案非常好。否则,剪切路径可能会变形。Temani Afif的回答指出,在不使用“objectBoundingBox”的情况下,图像的大小很重要。在这种情况下,svg中的单位与div / image中的像素相关联。 - Rob Monhemius

1
Clip-path不会被继承。建立新的剪切路径:'clipPath'元素 W3C
因此,将clip-path应用于父块不会使子元素被裁剪。
最好使用svg <image>标签替代<img>并将clip-path应用于它。
使用
作为自适应容器。

.wrapped {
width:25%;
height:25%;
}
#img1 {
clip-path:url(#cross);
}
<div class="wrapped">
<svg  viewBox="0 0 250 250">
  <defs>
    <clipPath id="cross">
      <rect y="110" x="137" width="90" height="90"/>
      <rect x="0" y="110" width="90" height="90"/>
      <rect x="137" y="0" width="90" height="90"/>
      <rect x="0" y="0" width="90" height="90"/>
    </clipPath>
  </defs> 

<image id="img1" width="100%" height="100%" xlink:href="https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"/>

</svg> 

</div>


你能详细说明一下你所说的父块和子元素是什么吗?它们是 SVG 内部的元素吗?如果是这样,我会怀疑 SVG 有问题,因为相同的 SVG clipPath 在图像上起作用。 - Rob Monhemius
@RMo <div id="clipped"> - 父级块SVG - 子元素。在您的第二个例子中。 - Alexandr_TT
我不明白这里的继承部分?我们没有任何子父关系,或者我漏掉了什么吗? - Temani Afif
@Temani Afif 在我指出的w3C链接中,明确写着clip-path: inherit NO。从示例中我理解到,OP想要将clip-path应用于包含图像的div内部。也许我过早地预测了OP的意愿 :) - Alexandr_TT
我猜继承是在解释另一件事,因为clip-path将影响元素的所有内容:https://jsfiddle.net/89r5t630/ ...也许子元素不会继承该值,但它们会受到其父元素之一的影响(如opacity,display等)。 - Temani Afif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接