理解 Css 的 Clip Path

·  阅读 804

最近看一篇文章包含 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%);
}
复制代码

circle-clip.png

.card 使用 clip-path后,可见区域只有一个蓝色圆,所有圆之外的内容是不可见的。

直角坐标系

在深入了解 clip-path的细节前,值得提下直角坐标系的运作。原点是左上角,x轴向右,y轴向下

coordinate-system.png

记住这一点,看一个简单的例子演示元素怎样被裁剪。在这例子中,剪切区域是一个大小100px的圆,它的中心在 0,0 (左上角)。

circle-in-origin.png

注意只有强调区域(暗蓝色)是用户可见的,圆之外的区域被裁剪了。问题是,我们怎样才能把整个圆演示出来?我们需要改变x和y轴的点。

100px-centercircle.png

圆心是在距左边x轴100px,上边的y轴100px。你现在明白直角坐标系的运作吧,我将会解释clip-path的可取的值。

Clip-Path 的值

Inset

inset 值定义一个嵌入的长方形。我们可以控制四个边,就像我们处理 marginpadding。以下例子演示一个区域的 inset 的边 (上下左右) 都是20px。

20pxinset.png

你可以扭其中一边,请看以下例子:

.card {
  clip-path: inset(20px 20px 50px 20px);
}
复制代码

20px-bottom-inset.png

问题是我们可以有圆边框的嵌入长方边?利用关键词 round ,当然可以!追加关键词 <border-radius>使角变圆。

.card {
  clip-path: inset(20px 20px 50px round 15px);
}
复制代码

roundcorner.png

(译者注: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);
}
复制代码

oval.png

多边形

对我来说,polygon() 是最有趣的。我们可以有能力去控制多个不同的x和y轴的值。

.card {
  clip-path: polygon(5% 5%, 95% 5%, 95% 95%, 5% 95%);
}
复制代码

polygon.png

我们可以用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");
}
复制代码

svgdemo.png

我们了解了 clip-path 的理论和它的可取值,是时候用它来实战探索一些用例。你准备好吗?

用例

斜角效果

在某些方面,你可能看见网站的一个区域会有细微斜角背景, 利用clip-path可以完全实现该效果。

angled-effect.png

你能猜出怎样实现斜角效果?我们需要使用 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()值的左边。

polygonad.png

一旦点击图标,可以在浏覧器编辑多边形了。

(译者注:只有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%);
}
复制代码

多重斜角效果

我有个问题,如果我们想要多重斜角区域?看下图:

multipleangle.png

我首先想到的是简单增加 box-shadowborder。不幸的是,上述属性是会被裁剪的,所以即使我们添加其中一个,它也不会如预期展现出来。

在这情况下,解决方法是利用多重元素,每一个有不同的裁剪点。以下是解决方法:

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

注意通过inset(50%),蓝色长方形完全不可月山竹山竹。是的,之所以是 50%,是因为我们从四边设定 inset。即是说,inset从长方形的边缩小至中心。

下图中,当用户滚动页面,inset用来展示图像。

isvisible.png

当图像处于可视窗口,下面的 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,创造一个简单的滚动效果。

Demo

不只如此,我们还能控制展示过渡的方向。我们只需要四边的其中一边的值。例如,如果我们想要至顶向下的过渡,底的值应该从 100% 至 0。下图解释上述原理。

insettransition.png

附上互动连接:

demo

悬停 以及 动画效果

利用 clip-path 来创造悬停动画效果的可能性是无穷的。考虑以下例子:

threeprices.png

我们需要把悬停效果增加至指定位置。利用 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;
}
复制代码

不只如此,我们能容易改变动画。我造了一个互动演示,可以通过选择框改变位置。

demo

如果你想深入了解更多动画效果,Adam Argyle先生创造一个非常有用的css动画库,它是100%依赖css的clip-pathTransition.css

连漪效果

连漪效果因 Material design的出现而流行。通过 clip-path,我们可以容易複现这效果。

ripple-effect.png

<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);
}
复制代码

demo

Clip-Path 值得一知的知识

不可见区域不接收 pointer 事件

当一个区域被裁剪,它之外的区域不接收任何 pointer事件。这意味着用户不能在不可见区域悬停。

你可以用相对值

你可否让 clip-path 相对于 font-size?你可以在 clip-path 利用 emrem

分类:
前端
标签: