使用CSS剪裁的教程实例

154 阅读5分钟

剪切和屏蔽在CSS中已经存在了一段时间,甚至有相当不错的浏览器支持。我最近做了一个项目,需要对显示在文本链接上方的工具提示使用剪切技术。

那些工具提示根据其内容有两种设计:

一种设计是包含纯文本的工具提示,其背景为纯色。

另一种设计是允许图像覆盖整个空间。

你可能认为文本工具提示根本不需要任何剪裁。一个伪元素可以被放置在底部来添加小缺口,对吗?你确实是完全正确的!因为工具提示的背景是一种普通的颜色,所以确实不需要CSS技巧之类的东西。

但是,在第二个设计中剪掉图片是事情变得有趣的地方......

以下是我开始做这个任务时的思维过程。

想法1:剪辑路径和多边形

CSSclip-path 属性允许我们用百分比值定义一个自定义的多边形来制作我们想要的路径。
如果你的路径形状足够简单,这种解决方案往往就足够了。在下面的演示中,我使用calc() 值来确保剪辑是完全响应的,而无论父体如何拉伸,小三角形都会保持相同的大小。

.tooltip {
  clip-path: polygon(
    0% 0%, // Top left point
    100% 0%, // Top right point
    100% calc(100% - 10px), // Bottom right point
    calc(50% + 10px) calc(100% - 10px), // Center right of the triangle
    50% 100%, // Tip of the triangle
    calc(50% - 10px) calc(100% - 10px), // Center left of the triangle
    0% calc(100% - 10px) // Bottom left point
  );
}

这个解决方案非常干净,但在我的情况下,还不够好,因为我没有一个直的三角形缺口,而是一个自定义形状。

想法2:剪辑路径和SVG

使用SVG路径似乎是一个不错的解决方案。首先,你导出你的SVG剪切路径,然后在你的CSS中使用它的url(#clipPathId) 值。

箭头是根据图像的比例来拉伸的。由于小缺口是整个路径形状的一部分,它的拉伸程度与路径的矩形部分的拉伸程度一样。

想法3:面具-图像

现在我发现了一个问题,那就是CSS的 [mask-image](https://css-tricks.com/almanac/properties/m/mask-image/)属性发现的。你可以将遮罩层结合起来想想看,这就像CSS中的background-image 。你可以在一个元素上应用多个梯度或图像。现在,如果你把所有这些层结合起来,生成你所需要的最终遮罩,会怎么样呢?

这正是我们在这里要做的,有两个层:

  1. 一个大的矩形,除了底部的条纹外,覆盖整个区块(绿色显示
  2. 箭头的图像(粉色所示)。

有了这个解决方案,矩形可以根据我们的工具提示的尺寸进行拉伸,而箭头将始终保持其固定尺寸。

下面所有的代码和演示都是无前缀的,演示中使用的是Autoprefixer。在我写这篇文章的时候,Edge, Chrome & Safari都需要前缀。

就像我们使用背景属性一样,我们将使用三个不同的遮罩属性来定义我们的两个层:

  • mask-image: 这个属性让我们用线性背景画出矩形,用内联SVG画出箭头。
  • mask-position: 矩形不需要一个位置(因为它是从左上角开始的),但箭头需要定位在中心-底部。
  • mask-repeat :我们需要避免重复两个图层;否则,线性渐变会在重复时覆盖整个元素。
.tooltip {
  mask-image:
    linear-gradient(#fff, #fff), /* Rectangle */
    url('data:image/svg+xml;utf8,'); /* Bottom arrow mask-position: */
    0 0, /* Rectangle */
    50% 100%; /* Bottom arrow */
  mask-size:
    100% calc(100% - 18px), /* Rectangle */
    38px 18px; /* Bottom arrow */
  mask-repeat: no-repeat;
}

更复杂的形状

让我们花样百出,深入研究一下这个技术。我从iOS上的iMessage应用中得到启发,试图用这种遮蔽技术再现同样的工具提示。

我不得不为我的遮罩画更多的层,以呈现每一个圆角:

  • 四个圆,每个角一个(红色显示)。
  • 一个水平矩形(蓝色显示
  • 一个垂直矩形(如绿色所示
  • 一个用于箭头的SVG(如黄色所示)。

完整的代码会有点长,因为我们有更多的层要画,但逻辑保持不变。角落是用四个径向梯度绘制的。为了填充矩形,我们需要两个矩形(一个垂直,一个水平),如上所示。最后,我们的小箭头,是使用内联SVG。

.tooltip {
  --radius: 25px;
  mask-image:
    radial-gradient(#fff (var(--radius) - 1), #fff0 var(--radius)), /* Top left corner */
    radial-gradient(#fff (var(--radius) - 1), #fff0 var(--radius)), /* Top right corner */
    radial-gradient(#fff (var(--radius) - 1), #fff0 var(--radius)), /* Bottom left corner */
    radial-gradient(#fff (var(--radius) - 1), #fff0 var(--radius)), /* Bottom right corner */
    linear-gradient(#fff, #fff), /* Horizontal gradient */
    linear-gradient(#fff, #fff), /* Vertical gradient */
    url('data:image/svg+xml;utf8,'); /* Bottom right icon */
  mask-position: 
    0 0, /* Top left corner */
    100% 0, /* Top right corner */
    0 100%, /* Bottom left corner */
    100% 100%, /* Bottom right corner */
    0 var(--radius), /* Horizontal gradient */
    var(--radius) 0, /* Vertical gradient */
    100% 100%; /* Bottom right icon */
  mask-size:
    (var(--radius) * 2) (var(--radius) * 2),  /* Top left corner */
    (var(--radius) * 2) (var(--radius) * 2),  /* Top right corner */
    (var(--radius) * 2) (var(--radius) * 2),  /* Bottom left corner */
    (var(--radius) * 2) (var(--radius) * 2),  /* Bottom right corner */
    100% calc(100% - #{var(--radius) * 2}), /* Horizontal gradient */
    calc(100% - #{var(--radius) * 2}) 100%, /* Vertical gradient */
    (39px / 2) (25px / 2); /* Bottom right icon */
  mask-repeat: no-repeat;
}

正如你所看到的,我们可以通过使用箭头的翻转版本并将其定位在不同的角落,创建一个箭头在左边或右边的版本。这个技巧在没有图像的工具提示上也能正常工作。但就像我在本文开头说的,如果你只有一个普通的背景需要样式,你可能不需要那么多CSS。