将具有混合(固定和百分比)值的 CSS 剪辑路径转换为 ​​SVG 剪辑路径

Posted

技术标签:

【中文标题】将具有混合(固定和百分比)值的 CSS 剪辑路径转换为 ​​SVG 剪辑路径【英文标题】:Transform CSS clip-path with mixed (fixed and percentage) values to SVG clip-path 【发布时间】:2019-05-13 13:20:47 【问题描述】:

我有一张使用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>

但问题是,无论卡片大小如何,我都无法使这个剪裁角具有固定大小。

【问题讨论】:

渐变是随机的还是定义的? @TemaniAfif 如果我能得到可以处理任意渐变或图像的解决方案,那就太好了。即使它不是 SVG 解决方案,但适用于所有现代浏览器。 添加了通用解决方案 【参考方案1】:

为了保持它的固定大小,您不能在 SVG 上使用 viewBox。只需剪下您需要的角落,让其他角落延伸很长一段距离,以便覆盖您可能需要的任何尺寸。在下面的示例中,我已将剪辑路径扩展到 (10000,10000)。

这里我们将渐变应用到 100% x 100% &lt;rect&gt;。这样渐变总是可以缩放以适应屏幕。然后我们将剪贴路径应用于矩形以获得缺口。

html, body 
  height: 100%;


.container 
  width: 50%;
  height: 50%;
<div class="container">
  <svg  >
    <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   fill="url(#grad1)" clip-path="url(#clip1)"/>
 </svg>
</div>

【讨论】:

我已经使用 SVG mask 找到了 solution,但你有我的支持,因为你的解决方案也可以工作,尽管这个 10000 值看起来很糟糕。所以还是谢谢! @Paul LeBeau 非常机智的回答!适用于所有现代浏览器 + Edge【参考方案2】:

如果渐变始终具有底部或顶部方向,您可以考虑使用倾斜变换和伪元素的技巧,如下所示:

.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>

【讨论】:

如果你想要我的反馈,那么我可以说我喜欢它工作得很好,所以你有我的支持,但我不喜欢它需要这么多代码,所以我会等待存在其他选项。 @VadimOvchinnikov 是的,你需要等待,因为我很确定 SVG 有办法。只需等待向导 ;) 但我喜欢用 CSS 进行黑客攻击:p【参考方案3】:

在 Stack Overflow in Russian 的帮助下使用 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"   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   fill="url(#grad1)" mask="url(#triangle-clip)" />
</svg>
</div>

【讨论】:

以上是关于将具有混合(固定和百分比)值的 CSS 剪辑路径转换为 ​​SVG 剪辑路径的主要内容,如果未能解决你的问题,请参考以下文章

固定导航上的 CSS 剪辑/剪辑路径在 Chrome 和 IE 中不合作

CSS,将内圈剪辑到图像

在 CSS 中创建结合百分比和静态(例如像素)值的网格的研究

将剪辑路径应用于父元素会导致子元素的动画不稳定

css中的单个固定位置剪切区域仅影响图像

固定缩略图比例大小和保持纵横比?