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

时间:2018-12-12 12:24:55

标签: css svg clipping clip-path

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

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

3 个答案:

答案 0 :(得分:3)

要保持固定大小,您不能在SVG上使用viewBox。只需修剪所需的角,然后使其他角延伸很长的距离,即可覆盖您可能需要的任何尺寸。在下面的示例中,我将剪切路径扩展到(10000,10000)。

在这里,我们将渐变应用于100%x 100%<rect>。这样可以使渐变始终缩放以适合屏幕。然后我们将clippath应用于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>

答案 1 :(得分: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>

答案 2 :(得分:1)

Stack Overflow in Russian使用SVG mask的帮助下,我的解决方案是

    static void Main(string[] args)
    {
        //Main App Process.
        if (args.Length == 0)
        {
            //Saves current process info to pass on command line.
            main = Process.GetCurrentProcess();
            mainProcessID = main.Id;

            //Initializes the helper process
            checker = new Process();
            checker.StartInfo.FileName = main.MainModule.FileName;
            checker.StartInfo.Arguments = mainProcessID.ToString();

            checker.EnableRaisingEvents = true;
            checker.Exited += new EventHandler(checker_Exited);

            //Launch the helper process.
            checker.Start();

            Application.Run(new MainForm()); // your winform app
        }
        else //On the helper Process
        {
            main = Process.GetProcessById(int.Parse(args[0]));

            main.EnableRaisingEvents = true;
            main.Exited += new EventHandler(main_Exited);

            while (!main.HasExited)
            {
                Thread.Sleep(1000); //Wait 1 second. 
            }

            //Provide some time to process the main_Exited event. 
            Thread.Sleep(2000);
        }
    }

    //Double checks the user not closing the checker process.
    static void checker_Exited(object sender, EventArgs e)
    {           
        //This only checks for the task manager process running. 
        //It does not make sure that the app has been closed by it. But close enough.
        //If you can think of a better way please let me know.
        if (Process.GetProcessesByName("taskmgr").Length != 0)
        {
            MessageBox.Show("Task Manager killed helper process.");

            //If you like you could kill the main app here to. 
            //main.Kill();
        }
    }

    //Only gets to run on the checker process. The other one should be dead. 
    static void main_Exited(object sender, EventArgs e)
    {
        //This only checks for the task manager process running. 
        //It does not make sure that the app has been closed by it. But close enough.
        //If you can think of a better way please let me know.

        if (Process.GetProcessesByName("taskmgr").Length != 0)
        {
            MessageBox.Show("Task Manager killed my application.");
        }
    }
.container {
  width: 200px;
  height: 200px;
}

svg {
  width: 100%;
  height: 100%;
}