最近看一篇文章包含 clip-path 的应用,发现自己对这CSS属性一知半解,决定要好好了解一下它。在网上搜了下,看到一篇文章叫 Understanding Clip Path in CSS,浅白又不失深度介绍 clip-path,看完后决定把它翻译,补充我自己的见解,算是自己的翻译 + 笔记。
懂英语的建议直接读原文:Understanding Clip Path in CSS
介绍
clip-path属性创造一个剪切区域,内容在该区域是可见的,而该区域之外是隐藏。以下例子演示一个圆形剪切区域。
.card {
background-color: #77cce9;
clip-path: circle(80px at 50% 50%);
}
.card 使用 clip-path后,可见区域只有一个蓝色圆,所有圆之外的内容是不可见的。
直角坐标系
在深入了解 clip-path的细节前,值得提下直角坐标系的运作。原点是左上角,x轴向右,y轴向下
记住这一点,看一个简单的例子演示元素怎样被裁剪。在这例子中,剪切区域是一个大小100px的圆,它的中心在 0,0 (左上角)。
注意只有强调区域(暗蓝色)是用户可见的,圆之外的区域被裁剪了。问题是,我们怎样才能把整个圆演示出来?我们需要改变x和y轴的点。
圆心是在距左边x轴100px,上边的y轴100px。你现在明白直角坐标系的运作吧,我将会解释clip-path的可取的值。
Clip-Path 的值
Inset
inset 值定义一个嵌入的长方形。我们可以控制四个边,就像我们处理 margin 或 padding。以下例子演示一个区域的 inset 的边 (上下左右) 都是20px。
你可以扭其中一边,请看以下例子:
.card {
clip-path: inset(20px 20px 50px 20px);
}
问题是我们可以有圆边框的嵌入长方边?利用关键词 round ,当然可以!追加关键词 <border-radius>使角变圆。
.card {
clip-path: inset(20px 20px 50px round 15px);
}
(译者注:inset加上round,配合 borderimage,可以做出多彩圆边框,详情请看:巧妙实现带圆角的渐变边框)
Circle
使用 circle(),我们需要半径和位置,以下是例子:
.card {
clip-path: circle(80px at 50% 50%);
}
圆的半径是80px,它的位置是距x和y轴50%。
Ellipse
利用 ellipse(),我们可以设定寛度和高度来创造一个椭圆形。
.card {
clip-path: ellipse(100px 80px at center);
}
多边形
对我来说,polygon() 是最有趣的。我们可以有能力去控制多个不同的x和y轴的值。
.card {
clip-path: polygon(5% 5%, 95% 5%, 95% 95%, 5% 95%);
}
我们可以用polygon设定多个点的值,画複杂的形状。
(译者注:整篇文章没有谈 polygon的细节,我去看 MDN 也搞不太懂。后来我发现一个网站: Clippy,可以可视化设定 polygon的属性,不用自己手动调参,非常好用)
Path
path() 允许我们使用SVG路径去裁剪一个特定的区域。浏覧器兼容性暂时不一致。要让它可在不同的浏覧器使用,我们需要内联 SVG,然后使用 url()作为 clip-path的值。
<svg class="svg">
<clipPath id="triangle" clipPathUnits="objectBoundingBox">
<path d="M0.05,0.05 h1 v1"></path>
</clipPath>
</svg>
.card {
clip-path: url("#triangle");
}
我们了解了 clip-path 的理论和它的可取值,是时候用它来实战探索一些用例。你准备好吗?
用例
斜角效果
在某些方面,你可能看见网站的一个区域会有细微斜角背景, 利用clip-path可以完全实现该效果。
你能猜出怎样实现斜角效果?我们需要使用 polygon()。
.section {
clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%);
}
某些情况下,去调整 polygon 的8个值是烦人的事情。我有小技巧,可以利用浏覧器去创造我们想要的形状。首先,我们需要增加如下属性:
.section {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
之后,我们需要检查在开发者工具下对应的元素。注意有一个小的多边形图标在 polygon()值的左边。
一旦点击图标,可以在浏覧器编辑多边形了。
(译者注:只有Firefox可以用,还不如我刚才给的方法)
使斜角效果相对于用户可视窗口宽度
我们还可以利用CSS的 calc()混合 CSS的可视窗口单位 (VM) 使角度相对于可视窗口宽度。我是从Kilian Valkhof的 Sloped edges with consistent angle in CSS
学到的。
.section {
clip-path: polygon(0 0, 100% 0, 100% calc(100% - 5vw), 0 100%);
}
多重斜角效果
我有个问题,如果我们想要多重斜角区域?看下图:
我首先想到的是简单增加 box-shadow 或 border。不幸的是,上述属性是会被裁剪的,所以即使我们添加其中一个,它也不会如预期展现出来。
在这情况下,解决方法是利用多重元素,每一个有不同的裁剪点。以下是解决方法:
<div class="hero">
<img src="bg.jpg" alt="" />
</div>
.hero {
position: relative;
min-height: 350px;
}
.hero img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
clip-path: polygon(0 0, 100% 0, 100% 80%, 0 90%);
}
.hero:after {
content: "";
position: absolute;
left: 0;
bottom: -20%;
z-index: -1;
width: 100%;
height: 100%;
background-color: #4545a0;
clip-path: polygon(0 0, 100% 0, 100% 80%, 0 90%);
}
我们有一个伪元素有相同大小和 clip-path 作为其他元素。不同之处是它通过 bottom -20% 和 z-index -1 处于父元素底下。我使用20%是因为它是 100 - 80 的结果。
滚动中展示
利用 IntersectionObserver API,当用户滚动页面,元素才展示 (译者注:懒加载)。
Inset
inset 是我发现对这效果最有用的clip-path值。你可能想为什么?我会在下一个图中告诉你。
注意通过inset(50%),蓝色长方形完全不可月山竹山竹。是的,之所以是 50%,是因为我们从四边设定 inset。即是说,inset从长方形的边缩小至中心。
下图中,当用户滚动页面,inset用来展示图像。
当图像处于可视窗口,下面的 javascript代码增加 is-visible class,我们因而可以通过滚动展示页面。
const images = document.querySelectorAll("img");
function check(entries) {
entries.map((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
observer.unobserve(entry.target);
}
});
}
const observer = new IntersectionObserver(check);
images.forEach((image) => observer.observe(image));
img {
clip-path: inset(50%);
transition: 1.2s ease-in;
}
img.is-visible {
clip-path: inset(0);
}
很简单吧?我们利用几行css和javascript,创造一个简单的滚动效果。
不只如此,我们还能控制展示过渡的方向。我们只需要四边的其中一边的值。例如,如果我们想要至顶向下的过渡,底的值应该从 100% 至 0。下图解释上述原理。
附上互动连接:
悬停 以及 动画效果
利用 clip-path 来创造悬停动画效果的可能性是无穷的。考虑以下例子:
我们需要把悬停效果增加至指定位置。利用 circle()达到这效果吧。
为了让例子更容易和更好维护,我们使用css变量,因而不会重複整个clip-path,我们只改变需要的css变量。
:root {
--pos: left center;
--size: 0;
}
.stats__item:before {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: #7777e9;
clip-path: circle(var(--size) at var(--pos));
transition: 0.4s linear;
}
.stats__item:hover:before {
--size: 300px;
}
不只如此,我们能容易改变动画。我造了一个互动演示,可以通过选择框改变位置。
如果你想深入了解更多动画效果,Adam Argyle先生创造一个非常有用的css动画库,它是100%依赖css的clip-path。Transition.css
连漪效果
连漪效果因 Material design的出现而流行。通过 clip-path,我们可以容易複现这效果。
<button class="button"><span>Sign up now</span></button>
.button {
position: relative;
}
.button span {
position: relative;
z-index: 1;
}
.button:before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: #fff;
opacity: 0.1;
clip-path: circle(0 at center);
transition: 0.3s ease-out;
}
.button:hover:before {
clip-path: circle(100px at center);
}
Clip-Path 值得一知的知识
不可见区域不接收 pointer 事件
当一个区域被裁剪,它之外的区域不接收任何 pointer事件。这意味着用户不能在不可见区域悬停。
你可以用相对值
你可否让 clip-path 相对于 font-size?你可以在 clip-path 利用 em 或 rem。