本文翻译自 Tricks to Cut Corners Using CSS Mask and Clip-Path Properties,略有删改
原作者:Temani Afif
我们最近使用CSS mask
属性创建花哨的边框,本文将使用CSS mask
和clip-path
来切元素的四个角!使用多种技术可以从任何元素的角切割不同的形状。在本文中,我们将考虑创建独特角落形状的现代技术,同时尝试使用可重用代码,该代码允许我们仅通过调整变量即可产生不同的结果。
查看此在线工具,了解我们正在构建的内容。这是一个CSS生成器,你可以选择不同的形状、角落和大小,可实时获得CSS代码!
我们主要有两种类型的切割:一种是圆形的,一种是倾斜的。对于每个类型,我们可以选择获取完整的形状或纯边框的形状,以及可以选择要切哪个方向的角。
与上一篇文章一样,我们将大量使用CSS mask
属性。如果你不熟悉它,建议在继续之前阅读我写的快速入门书。
圆形切角
对于圆形切割,我们使用radial-gradient()
。切割四个角落时,逻辑解决方案则是创建四个渐变,每个角落一个:
每个圆形切割部分占整个元素尺寸的四分之一。如上图所示,左上角切割代码如下:
radial-gradient(circle 30px at top left, #0000 98%, red) top left;
以上代码的翻译后,即在左上角呈现一个半径为30px圆圈。主要颜色是透明的(#0000),其余是red。其他三个渐变的逻辑相同。这里的关键字circle可以省略,因为已经明确的指定了一个半径值。
就像我在上一篇文章中所做的那样,这次我将使用略大或更小的值,以避免糟糕的视觉效果。在这里,我使用98%而不是100%来避免锯齿状的边缘,51%而不是50%来创建渐变之间的重叠并避免空白。本文继续遵循这一逻辑。在实际开发中,你会发现添加或删除1%或1deg通常会带来良好的视觉效果。
接下来将此逻辑应用于CSS mask
属性,效果如下:
核心CSS代码如下:
.mask { -webkit-mask: radial-gradient(circle 30px at top left ,#0000 98%,#000) top left, radial-gradient(circle 30px at top right,#0000 98%,#000) top right, radial-gradient(circle 30px at bottom left ,#0000 98%,#000) bottom left, radial-gradient(circle 30px at bottom right,#0000 98%,#000) bottom right; -webkit-mask-size:51% 51%; -webkit-mask-repeat:no-repeat; }
上面的代码有很多数值是重复的,我们可以稍微优化一下该代码:
--g: #0000 98%,#000; --r: 30px; mask: radial-gradient(var(--r) at 0 0 ,var(--g)) 0 0, radial-gradient(var(--r) at 100% 0 ,var(--g)) 100% 0, radial-gradient(var(--r) at 0 100%,var(--g)) 0 100%, radial-gradient(var(--r) at 100% 100%,var(--g)) 100% 100%; mask-size: 51% 51%; mask-repeat: no-repeat;
这样我们可以对冗余值使用自定义属性,作为个人偏好,我使用位置的数字值而不是关键字。
在生成器中,将使用以下语法,省去mask-size
和mask-repeat
,使用简写方式:
--g: #0000 98%,#000; --r: 30px; mask: radial-gradient(var(--r) at 0 0 ,var(--g)) 0 0 /51% 51% no-repeat, radial-gradient(var(--r) at 100% 0 ,var(--g)) 100% 0 /51% 51% no-repeat, radial-gradient(var(--r) at 0 100%,var(--g)) 0 100%/51% 51% no-repeat, radial-gradient(var(--r) at 100% 100%,var(--g)) 100% 100%/51% 51% no-repeat;
我们可以使用更少的渐变吗?
当然!一个渐变也可以完成这个效果。以下动图hover
效果就是基于一个渐变实现:
在这里,我们定义了一个没有尺寸的radial-gradient()
,默认情况下它是100%的高度和100%宽度。这让我们在中间有一个洞。我们将渐变平移到图像宽度和高度的一半,将孔移动到一个角落。由于默认情况下,CSS mask
重复,因此我们在每个角落都得到相同的效果。我们有四个切角,只使用了一个渐变!
这种方法的唯一缺点是,我们需要提前知道元素的宽度和高度。
我们能用 -50% 而不是一半的宽度和高度吗?
不幸的是,在这里无法做到这一点,因为当与CSS mask-position
属性一起使用时,百分比的行为与像素值不同,比较难处理。
我有一个详细的堆栈溢出答案来解释差异。它涉及
background-position
,但相同的逻辑适用于CSS mask-position
属性。
然而,我们可以使用一些技巧来使其与百分比值一起工作,无需知道宽度或高度。当渐变(或背景图层)的宽度和高度等于元素时,我们无法使用百分比值移动它。所以我们需要改变它的尺寸!
定义一个等于99.5% 99.5%的尺寸。将宽度和高度降低了0.5%,此时基本保持相同的视觉结果,因为我们不会注意到100%和99.5%之间的巨大差异。现在我们的渐变尺寸与100%不同,我们可以使用百分比值移动它。
要将其移动一半的宽度和高度,我们需要使用这个方程:
100% * (50/(100 - 99.5)) = 100% * 100 = 10000%
看着是一个比较奇怪的值,但是是可以正常运行的。
mask: radial-gradient(30px,#0000 98%,#000) 10000% 10000%/99.5% 99.5%
这个技巧用的很好。无论元素的大小是多少,我们只能用一个渐变切割四个角落。但是当元素的宽度或高度是小数值时,这种方法有一个很小的缺点。以下是一个宽度等于150.5px的图像示例:
使用99.5%和150.5px将产生四舍五入问题,从而破坏计算,导致mask有一定的错位。因此,请谨慎使用这种方法。
有一个只有一个渐变的解决方案,没有四舍五入问题。使用以下代码:
mask: radial-gradient(30px at 30px 30px,#0000 98%,#000) -30px -30px
技巧是在左上角创建一个圆,通过用负偏移量移动它,我们覆盖了四个角落。将下方悬停在下方,看看这个技巧。
这个方法很完美,因为它使用一种渐变,且没有四舍五入的问题。但它有一个缺点,半径的值被使用5次。但是我们可以使用自定义属性进行简化:
--r: 30px; mask: radial-gradient(var(--r) at var(--r) var(--r),#0000 98%,#000) calc(-1*var(--r)) calc(-1*var(--r))
让我们快速回顾一下我们刚刚介绍的三种方法:
- 第一种方法使用四个渐变,在使用方面没有缺点,它适用于任何类型的元素和尺寸。但它的代码量很冗长。
- 第二种方法使用一种渐变,但在某些情况下可能会有偏移不准确的情况。它适用于固定尺寸的元素。
- 第三种方法使用一种渐变,没有四舍五入问题。这是其中的完美方法,但它需要在渐变值内多次使用半径。
只切割部分角落
现在我们已经看到了所有角落的案例,接下来让我们禁用其中一些。使用第一种方法,任何我们想保持未切割的角落,我们只需删除其渐变并调整剩余内容的大小。
要禁用右上角的时候:
- 移除了右上角的渐变(蓝色渐变)。
- 此时有一个空角落,所以增加了红色渐变(或紫色渐变)的大小,以覆盖剩余的空间。
在这里可以做多少可能性和组合。如果需要切割N个角(其中N范围从1到4),则使用N个渐变。我们只需要正确设置每个的大小,以便填满整个空间。
只有一个渐变的其他方法呢?我们需要使用另一个渐变!这两种方法只使用一个radial-gradient()
来切割角落,因此我们将依靠另一个渐变来“隐藏”切割。我们可以使用带有四个部分的conic-gradient()
来完成此效果:
conic-gradient(red 25%, blue 0 50%, green 0 75%, purple 0)
conic-gradient()
会覆盖radial-gradient()
,这样就不会有切角。让我们将conic-gradient()
中的一种颜色更改为透明。例如,将右上角改为透明,就是下面的效果:
核心代码如下:
conic-gradient(#0000 25%,blue 0 50%,green 0 75%,purple 0)
通过将conic-gradient()
的颜色从不透明更改为透明,可以实现我们想要切割的角落,并获得各种可能的组合。
- 要切割四个角落,第一种方法需要四个渐变,而第三个方法只需要一个渐变,所以我们使用后者。
- 要切割一个角落,第一种方法需要一个渐变,而第三个方法需要两个渐变,因此您可以使用第一个渐变。
- 要切割两个角落,两者都使用两个渐变。
- 要切割三个角落,一个方法将使用三个渐变,另一个方法仅使用两个渐变。
以上介绍了每个案例选择适当的方法,我们总共不需要超过两个渐变。但在实际应用中,您应该选择更优化简洁的代码。