clip-path 实现不规则图形及溢出场景
本章节开始介绍新的属性 clip-path,该元素主要用于裁剪元素的可视区域。
clip-path 基本用法
clip-path 的基本语法如下:
clip-path: [ shape() | url()] | none;clip-path 可以接受一个 shape() 函数,也可以接受一个 url() 函数,还可以接受 none,表示不裁剪。
shape() 函数可以接受 inset(), circle(), ellipse(), polygon() 等函数,这些函数都是裁剪的形状。url() 函数可以接受一个 SVG 的 URL,表示裁剪的形状。
常见的裁剪形状如下:
/* 裁剪为圆形 */
clip-path: circle(50px at center);
/* 裁剪为椭圆 */
clip-path: ellipse(50px 30px at center);
/* 裁剪为矩形 */
clip-path: inset(10px 20px 30px 40px);
/* 裁剪为多边形 */
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);效果如下图所示:

具体效果可查看 clip-path 基本用法
clip-path 括号内的参数都是元素的坐标点,这些坐标点都是相对于元素左上角的位置。
clip-path 直接写会不太方便,社区有一些在线生成工具,可以帮助开发者更好的使用 clip-path,比如 CSS clip-path。它包含了多种常用的图形,并且可以调整图形坐标的参数,底部还能实时更新最新的参数代码。

用 clip-path 实现常见不规则图形
还是用之前的例子,之前使用 mask 实现了内切角的效果,现在可以借助 clip-path 快速实现效果,这样背景色可以直接任意定制,无论是渐变还是纯色都不在话下。
div {
width: 200px;
height: 100px;
background: linear-gradient(45deg, #ff7e5f, #feb47b);
clip-path: polygon(
15px 0,
calc(100% - 15px) 0,
100% 15px,
100% calc(100% - 15px),
calc(100% - 15px) 100%,
15px 100%,
0 calc(100% - 15px),
0 15px
);
}
在实现不规则多边形效果上,clip-path 比 mask 更为直观,而且代码量更少。如果要实现箭头图形效果:

如果用 mask ,虽然也可以做到,但是代码量会很繁琐,如果用 clip-path,很轻松就能实现效果。
div {
width: 200px;
height: 100px;
margin: 0 auto;
background: linear-gradient(90deg, skyblue, blue);
clip-path: polygon(
0 0,
calc(100% - 50px) 0,
100% 50%,
calc(100% - 50px) 100%,
0 100%,
50px 50%
);
}具体效果可查看 clip-path 实现不规则图形
clip-path 的局限性
clip-path 通过裁剪实现不规则图形效果,但 clip-path 并不是万能的,它也有一些局限性。
它最大的局限性在于,无法作用完整的边框。以上方两个例子为例,各自添加一个边框,看看效果如何。
div {
border: 2px solid #333;
}
.foo {
width: 200px;
height: 100px;
margin: 0 auto 20px;
background: linear-gradient(45deg, #ff7e5f, #feb47b);
clip-path: polygon(
15px 0,
calc(100% - 15px) 0,
100% 15px,
100% calc(100% - 15px),
calc(100% - 15px) 100%,
15px 100%,
0 calc(100% - 15px),
0 15px
);
}
.box {
width: 200px;
height: 100px;
margin: 0 auto;
background: linear-gradient(90deg, skyblue, blue);
clip-path: polygon(
0 0,
calc(100% - 50px) 0,
100% 50%,
calc(100% - 50px) 100%,
0 100%,
50px 50%
);
}
这是因为 clip-path 实际做的是切割图形,而边框实际作用在整体 div 上,因此被切割后的部分无法显示边框。
如果在切割裁剪完图形之后,又想要添加边框,该如何实现?
filter: drop-shadow()
box-shadow 是给整个盒子添加阴影效果,而 drop-shadow() 是创建一个符合当前元素本身形状的阴影,因此可以使用这个黑科技,给切割后的图形添加阴影,视觉上实现边框效果。
<div class="father">
<div class="foo"></div>
</div>
<div class="father">
<div class="box"></div>
</div>.father {
width: 200px;
height: 100px;
background: transparent;
margin: 0 auto 20px;
filter: drop-shadow(0 0 1px #000);
}
.foo {
width: 200px;
height: 100px;
margin: 0 auto 20px;
background: linear-gradient(45deg, #ff7e5f, #feb47b);
clip-path: polygon(
15px 0,
calc(100% - 15px) 0,
100% 15px,
100% calc(100% - 15px),
calc(100% - 15px) 100%,
15px 100%,
0 calc(100% - 15px),
0 15px
);
}
.box {
width: 200px;
height: 100px;
margin: 0 auto;
background: linear-gradient(90deg, skyblue, blue);
clip-path: polygon(
0 0,
calc(100% - 50px) 0,
100% 50%,
calc(100% - 50px) 100%,
0 100%,
50px 50%
);
}具体效果可查看 drop-shadow 模拟边框
注意
想要实现效果,需要注意 filter: drop-shadow() 需要添加在父元素上,因为 drop-shadow() 是创建一个符合当前元素本身形状的阴影,因此需要将阴影作用在父元素上。
clip-path 的坐标可以是负数,可以超出 100%
最常见的使用的 clip-path: polygon() 中,polygon() 内需要填入具体的数值,但是这里面的值可以是负数,可以超出 100% 。
下面来举一个例子实现这个功能。
<div>
<img src="https://picsum.photos/100/100?random=2" alt="" />
</div>div {
display: flex;
align-items: center;
justify-content: center;
position: relative;
width: 100px;
height: 100px;
margin: 0 auto;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
transform: translate(-50%, -50%);
border: 3px solid red;
}
img {
width: 120%;
height: 120%;
}
}
有一个 img ,宽高都是父盒子的 120%,下面对它做裁剪处理。
div {
display: flex;
align-items: center;
justify-content: center;
position: relative;
width: 300px;
height: 300px;
margin: 0 auto;
clip-path: polygon(-5% -19%, 100% -3%, 100% 128%, -1% 100%);
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
transform: translate(-50%, -50%);
border: 3px solid red;
}
img {
width: 120%;
height: 120%;
}
}添加后元素实现裁剪的效果,因此可以得出结论,clip-path 不仅仅能控制元素内的裁剪,对超出元素范围的内容一样有裁剪的能力!
那么这个能力有什么用呢?下面看一个著名游戏的封面布局图。

可以看到很多图片都是不规则型,且大小超出了父容器。可能会有人想,这个效果直接找 UI 切图不就好了?那如果添加鼠标悬停效果呢?

这就没法用切图就直接解决了,这个效果的核心效果就是 display: grid 布局结合 clip-path 裁剪实现的。
用 clip-path 实现指定区域的 overflow: hidden
clip-path 可以控制区域外的裁剪,那么也意味着,可以用来指定溢出隐藏的区域。什么意思呢?下面看看这个效果图。

可以看到,只有在 y 轴溢出部分才会隐藏,而 x 轴溢出部分则不会隐藏。这个效果直接设置 overflow: hidden 是无法实现的。
div {
width: 200px;
height: 200px;
clip-path: polygon(-1000% 0, 1000% 0, 1000% 100%, -1000% 100%);
}上方代码中,横向用了上一节提到的裁剪可以设为负数和超出 100% 的知识点,裁剪了 1000% ,因此横向溢出部分不会隐藏,而纵向裁剪了 100% ,这样整个裁剪区域画成一个超大的矩形形状,因此纵向溢出部分会隐藏。
以此类推:
div {
clip-path: polygon(0 0, 1000% 0, 100% 1000%, 0 0); /* 只允许右侧溢出 */
}
div {
clip-path: polygon(
-1000% 0,
100% 0,
100% 1000%,
-1000% 1000%
); /* 只允许左侧和下侧溢出 */
}总结
本章节主要讲了 clip-path 的基本用法和见识了它强大的功能,主要有:
- 与
SVG类似,它是一个通过裁剪来创建可视区域的属性,区域内显示,区域外隐藏,因此可以用来创建不规则图形。属性不需要死记硬背,可以访问在线工具 CSS clip-path 来生成。 clip-path裁剪后的图形无法添加边框,可以使用filter: drop-shadow()来模拟边框效果。clip-path的坐标可以是负数,可以超出 100% ,因此可以实现超出父元素范围的裁剪效果。在部分overflow属性无法使用的情况下,可以尝试使用clip-path来实现。