将使用混合(固定值和百分比)的 CSS clip-path 转换为 SVG clip-path

5

我有一张带有渐变和使用clip-path剪切角的卡片图片:

.card {
  width: 200px;
  height: 200px;
  background: linear-gradient(to bottom, blue, green);
  clip-path: polygon(20px 0, 100% 0, 100% 100%, 0 100%, 0 20px);
}
<div class="card"></div>

裁剪的角必须具有固定的大小,而不受卡片大小的影响,因此我使用像素来裁剪角。

但是,目前浏览器对于clip-path的支持并不理想,因此我尝试将这个HTML和CSS转换为SVG。

.container {
  width: 200px;
  height: 200px;
}
<div class="container">
  <svg viewBox="0 0 100 100" clip-path="url(#myClip)">
    <defs>
      <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
        <stop offset="100%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
      </linearGradient>
    </defs>
  
    <polygon points="20,0 100,0 100,100 0,100 0,20" fill="url(#grad1)" />
 </svg>
</div>

但问题在于,我无法使这个剪切的角落具有固定的大小,而不管卡片的尺寸如何。


梯度将是随机的还是已定义的? - Temani Afif
@TemaniAfif 如果我能得到一个可以与任意渐变或图像一起使用的解决方案,那就太好了。即使它不是SVG解决方案,但它可以在每个现代浏览器中工作。 - Vadim Ovchinnikov
增加了通用解决方案。 - Temani Afif
3个回答

3
为了保持固定大小,你不能在SVG上使用viewBox。只需剪裁所需的角落并使其他角落延伸很长,以便覆盖可能需要的任何大小。在下面的示例中,我将剪辑路径扩展到(10000,10000)。
在这里,我们将渐变应用于100% x 100%的<rect>。这样,渐变始终按比例缩放以适合屏幕。然后,我们将剪辑路径应用于矩形以获得凹口。

html, body {
  height: 100%;
}

.container {
  width: 50%;
  height: 50%;
}
<div class="container">
  <svg width="100%" height="100%">
    <defs>
      <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
        <stop offset="100%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
      </linearGradient>
      <clipPath id="clip1">
        <polygon points="20,0 10000,0 10000,10000 0,10000 0,20"/>
      </clipPath>
    </defs>
  
    <rect width="100%" height="100%" fill="url(#grad1)" clip-path="url(#clip1)"/>
 </svg>
</div>


我已经找到了使用SVG mask解决方案,但你得到了我的点赞,因为你的解决方案也能够工作,尽管这个10000值看起来有些hacky。所以无论如何,还是谢谢! - Vadim Ovchinnikov
@Paul LeBeau 非常机智的回答!适用于所有现代浏览器和 Edge - Alexandr_TT

1

如果渐变始终具有底部或顶部方向,您可以考虑使用倾斜变换和伪元素来实现以下效果:

.card {
  width: 200px;
  height: 200px;
  padding-top: 20px;
  background-image: linear-gradient(to bottom, blue,red,yellow,green); 
  background-clip:content-box;
  background-size:100% 200px; /*same as height*/
  position: relative;
  z-index:0;
  overflow:hidden;
  box-sizing: border-box;
  display:inline-block;
}

.card:before {
  content: "";
  position: absolute;
  z-index:-1;
  top: 0;
  padding: inherit;
  left: 0;
  right: 0;
  background-image: inherit;
  background-size:inherit;
  transform: skewX(-45deg);
  transform-origin: left bottom;
}

body {
  background:pink;
}
<div class="card"></div>
<div class="card" style="background-image:linear-gradient(to top,white,purple,green ,red 90%, blue"></div>

对于任何渐变或者图像,你可以添加额外的元素来矫正偏斜:

.card {
  width: 200px;
  height: 200px;
  padding-top: 20px;
  background-image: linear-gradient(to bottom, blue,red,yellow,green); 
  background-clip:content-box;
  background-size:auto 200px; /*same as height*/
  position: relative;
  z-index:0;
  overflow:hidden;
  box-sizing: border-box;
  display:inline-block;
}
.image {
  background-size:cover; /*less restriction when it comes to image*/
}


.card span,
.card span::before {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  background-image: inherit;
  background-size:inherit;
  transform-origin: left bottom;
}

.card span {
  z-index:-1;
  padding: inherit;
  transform: skewX(-45deg);
  overflow:hidden;
}
.card span:before {
   content:"";
   bottom:0;
   transform: skewX(45deg);
}

body {
  background:pink;
}
<div class="card">
<span></span>
</div>
<div class="card" style="background-image:linear-gradient(60deg,white,purple,green ,red 90%, blue)">
<span></span>
</div>

<div class="card image" style="background-image:url(https://picsum.photos/400/400?image=0)">
<span></span>
</div>

<div class="card image" style="background-image:url(https://picsum.photos/600/600?image=15)">
<span></span>
</div>


如果你想要我的反馈,那么我可以说我喜欢它的表现很好,所以我会给你点赞,但我不喜欢它需要那么多代码,所以我会等待是否存在其他选项。 - Vadim Ovchinnikov
@VadimOvchinnikov 当然可以,你需要等待,因为我非常确定用SVG有方法。只需等待巫师们的出现 ;) 但我喜欢用CSS来hack。 - Temani Afif

1

俄罗斯的Stack Overflow的帮助下,使用SVG mask,我的解决方案如下:

.container {
  width: 200px;
  height: 200px;
}

svg {
  width: 100%;
  height: 100%;
}
<div class="container">
  <svg>
    <defs>
      <mask id="triangle-clip">
        <rect x="0" y="0" width="100%" height="100%" fill="#fff" />
        <path d="M0,20 v-20 h20 z" fill="#000" />
      </mask>

    <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" style="stop-color:rgb(0,0,255);stop-opacity:1" />
      <stop offset="100%" style="stop-color:rgb(0,255,0);stop-opacity:1" />
    </linearGradient>
  </defs>
  <rect width="100%" height="100%" fill="url(#grad1)" mask="url(#triangle-clip)" />
</svg>
</div>


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