CSS:使用背景剪裁、mask制作3D酷炫悬停效果教程

327 阅读11分钟

我们现在已经走过了一系列关于CSS悬停效果的有趣方法的帖子。我们从一堆使用CSSbackground 属性的例子开始,然后转到了text-shadow 属性,在技术上我们没有使用任何阴影。我们还将它们与CSS变量和calc() ,以优化代码并使其易于管理。

在这篇文章中,我们将在这两篇文章的基础上,创建更复杂的CSS悬停动画。我们将讨论背景剪裁、CSS掩码,甚至是3D视角的问题。换句话说,我们这次将探索高级技术,并挑战CSS在悬停效果方面的极限。

酷炫的悬停效果系列:

  1. 使用背景属性的酷炫悬停效果
  2. 使用CSS文本阴影的酷炫悬停效果
  3. 使用背景剪裁、遮罩和3D的酷炫悬停效果*(你在这里!*)。

这里只是我们正在做的一个尝试。

悬停效果使用background-clip

让我们来讨论一下 background-clip.这个CSS属性接受一个text 关键字值,允许我们将梯度应用于元素的文本而不是实际的背景

因此,举例来说,我们可以像使用color 属性一样,在悬停时改变文本的颜色,但这种方式可以使颜色变化成为动画。

我所做的只是在元素中添加background-clip: texttransitionbackground-position 。不需要比这更复杂!

但是,如果我们结合不同背景剪裁值的多个渐变,我们可以做得更好。

在这个例子中,我使用了两个不同的梯度和两个值,background-clip 。第一个背景渐变被剪切到文本上(感谢text 值)以设置悬停时的颜色,而第二个背景渐变创造了底部的下划线(感谢padding-box 值)。其他的东西都是直接从我们在这个系列的第一篇文章中所做的工作中复制的。

悬停效果如何,条形图从上到下滑动的方式,看起来就像文字被扫描,然后上色。

这一次,我改变了第一个渐变的大小来创建线条。然后我用另一个更新文本颜色的渐变来滑动它,以创造幻觉你可以在这支笔中直观地看到发生了什么。

我们只是触及了我们可以用我们的background-clipping powers做什么的表面!然而,这种技术可能是你想避免在生产中使用的,因为众所周知,Firefox有很多background-clip 。Safari也有支持问题。这样一来,只有Chrome浏览器对这种东西有可靠的支持,所以在我们继续的时候也许可以打开它。

让我们继续使用另一个悬停效果,background-clip

你可能在想,与我们刚才的内容相比,这个看起来超级简单 - 你是对的,这里没有什么花哨的东西。我所做的只是滑动一个梯度,同时增加另一个梯度的大小。

但是,我们在这里要看的是高级的悬停效果,对吗?让我们把它改变一下,当鼠标光标离开元素时,动画会有所不同。同样的悬停效果,但动画的结局不同。

让我们来剖析一下代码:

.hover {
  --c: #1095c1; /* the color */

  color: #0000;
  background: 
    linear-gradient(90deg, #fff 50%, var(--c) 0) calc(100% - var(--_p, 0%)) / 200%, 
    linear-gradient(var(--c) 0 0) 0% 100% / var(--_p, 0%) no-repeat,
    var(--_c, #0000);
  -webkit-background-clip: text, padding-box, padding-box;
          background-clip: text, padding-box, padding-box;
  transition: 0s, color .5s, background-color .5s;
}
.hover:hover {
  color: #fff;
  --_c: var(--c);
  --_p: 100%;
  transition: 0.5s, color 0s .5s, background-color 0s .5s;
}

我们有三个背景层--两个梯度和使用--_c 变量定义的background-color ,最初设置为透明(#0000)。在悬停时,我们将颜色改为白色,将--_c 变量改为主色(--c)。

下面是在该transition 上发生的事情。首先,我们给所有的东西应用一个过渡,但是我们把colorbackground-color 延迟到0.5s 来创造滑动的效果。紧接着,我们改变了colorbackground-color 。你可能会注意到没有视觉上的变化,因为文本已经是白色的了(由于第一个渐变),背景已经被设置成主色了(由于第二个渐变)。

然后,当鼠标移出时,我们对所有的东西应用一个即时变化(注意0s 的延迟),除了colorbackground-color 有一个过渡。这意味着我们把所有的梯度放回它们的初始状态。同样,你可能不会看到视觉上的变化,因为文字colorbackground-color 在悬停时已经改变了。

最后,我们应用颜色的渐变和一个background-color ,以创建动画的鼠标离开部分。我知道,这可能是很难掌握的,但你可以通过使用不同的颜色来更好地可视化这个技巧。

将上述内容多次悬停,你会看到悬停时的动画属性和鼠标移出时的动画属性。这样你就可以理解我们是如何为同一个悬停效果达到两种不同的动画效果的。

让我们不要忘记我们在本系列的前几篇文章中使用的DRY切换技术,通过只使用一个变量进行切换来帮助减少代码量:

.hover {
  --c: 16 149 193; /* the color using the RGB format */

  color: rgb(255 255 255 / var(--_i, 0));
  background:
    /* Gradient #1 */
    linear-gradient(90deg, #fff 50%, rgb(var(--c)) 0) calc(100% - var(--_i, 0) * 100%) / 200%,
    /* Gradient #2 */
    linear-gradient(rgb(var(--c)) 0 0) 0% 100% / calc(var(--_i, 0) * 100%) no-repeat,
    /* Background Color */
    rgb(var(--c)/ var(--_i, 0));
  -webkit-background-clip: text, padding-box, padding-box;
          background-clip: text, padding-box, padding-box;
  --_t: calc(var(--_i,0)*.5s);
  transition: 
    var(--_t),
    color calc(.5s - var(--_t)) var(--_t),
    background-color calc(.5s - var(--_t)) var(--_t);
}
.hover:hover {
  --_i: 1;
}

如果你想知道我为什么要用RGB语法来表示主色,那是因为我需要玩一下alpha透明度。我也在使用变量--_t ,以减少在transition 属性中使用的冗余计算。

在我们进入下一部分之前,这里有更多我前段时间做的依靠background-clip 的悬停效果的例子。详述每一个例子会太长,但通过我们目前所学到的,你可以很容易地理解这些代码。在不看代码的情况下,单独尝试其中的一些,可以起到很好的启发作用。

我知道,我知道。这些都是疯狂的、不常见的悬停效果,我意识到它们在大多数情况下是太多了。但这就是练习和学习CSS的方法。记住,我们在挑战CSS悬停效果的极限。悬停效果可能是一种新奇的东西,但我们正在沿途学习新的技术,这些技术肯定可以用于其他方面。

使用CSS的悬停效果mask

你猜怎么着?CSSmask 属性使用梯度的方式与background 属性相同,所以你会发现我们接下来要做的东西是非常直接的。

让我们从建立一个花哨的下划线开始。

我在那个演示中使用background ,创建一个之字形的底边。如果我想在下划线上应用一个动画,仅用背景属性来做会很繁琐。

输入CSSmask

这段代码可能看起来很奇怪,但其逻辑仍然与我们之前所有的背景动画相同。mask 是由两个渐变组成的。第一个渐变被定义为不透明的颜色,覆盖了内容区域(由于content-box 的值)。这第一个渐变使文本可见,并隐藏了底部的人字形边框。content-boxmask-clip 值,它的行为与background-clip

linear-gradient(#000 0 0) content-box

第二个渐变将覆盖整个区域(感谢padding-box )。这一个的宽度是用--_p 变量定义的,它将被放置在元素的左边。

linear-gradient(#000 0 0) 0 / var(--_p, 0%) padding-box

现在,我们要做的就是在悬停时改变--_p 的值,为第二个渐变创造一个滑动效果,并显示出下划线。

.hover:hover {
  --_p: 100%;
  color: var(--c);
}

下面的演示使用遮罩层作为背景,以更好地看到发生的技巧。想象一下,绿色和红色部分是该元素的可见部分,而其他部分都是透明的。如果我们使用同样的渐变,这就是遮罩的作用。

有了这样的技巧,我们可以很容易地通过简单地使用不同的梯度配置与mask 属性来创造很多的变化。

该演示中的每个例子都对mask 使用了稍微不同的梯度配置。也请注意,代码中背景配置和遮罩配置之间的分离。它们可以被独立管理和维护。

让我们改变背景配置,用波浪形下划线代替之字形下划线。

另一个悬停效果的集合!我保留了所有的遮罩配置,并改变了背景以创造一个不同的形状。现在,你可以理解我是如何在没有伪元素的情况下达到400个悬停效果的--而且我们还可以有更多的效果!

这里有一个挑战给你。 最后一个演示中的边框是一个使用mask 属性来显示的梯度。你能弄清楚这个动画背后的逻辑吗?乍一看可能很复杂,但它与我们看过的其他大多数依靠梯度的悬停效果的逻辑超级相似。请在评论中发表你的解释!

三维的悬停效果

你可能认为用一个元素创造一个3D效果是不可能的(而且不需要借助于伪元素!),但CSS有办法实现它。

你所看到的并不是一个真正的3D效果,而是在2D空间中的一个完美的3D幻觉,它结合了CSS的background,clip-path, 和transform 属性。

Breakdown of the CSS hover effect in four stages.

这个技巧看起来像是我们在与一个3D元素互动,但我们只是在使用2D战术来绘制一个3D盒子

我们要做的第一件事是定义我们的变量。

--c: #1095c1; /* color */
--b: .1em; /* border length */
--d: 20px; /* cube depth */

然后我们创建一个透明的边框,其宽度使用上述变量。

--_s: calc(var(--d) + var(--b));
color: var(--c);
border: solid #0000; /* fourth value sets the color's alpha */
border-width: var(--b) var(--b) var(--_s) var(--_s);

元素的顶部和右侧都需要等于--b 的值,而底部和左侧则需要等于--b--d 的总和(也就是--_s 变量)。

对于技巧的第二部分,我们需要定义一个梯度,覆盖我们之前定义的所有边界区域。A conic-gradient就可以了。

background: conic-gradient(
  at left var(--_s) bottom var(--_s),
  #0000 90deg,var(--c) 0
 ) 
 0 100% / calc(100% - var(--b)) calc(100% - var(--b)) border-box;

Diagram of the sizing used for the hover effect.

我们为这个技巧的第三部分添加另一个梯度。这个将使用两个半透明的白颜色值,与之前的第一个渐变重叠,创造出主色的不同色调,给我们带来阴影和深度的幻觉。

conic-gradient(
  at left var(--d) bottom var(--d),
  #0000 90deg,
  rgb(255 255 255 / 0.3) 0 225deg,
  rgb(255 255 255 / 0.6) 0
) border-box

Showing the angles used to create the hover effect.

最后一步是应用一个CSSclip-path来切角,以获得那种长阴影的感觉。

clip-path: polygon(
  0% var(--d), 
  var(--d) 0%, 
  100% 0%, 
  100% calc(100% - var(--d)), 
  calc(100% - var(--d)) 100%, 
  0% 100%
)

Showing the coordinate points of the three-dimensional cube used in the CSS hover effect.

这就是全部我们刚刚制作了一个3D矩形,除了两个渐变和一个clip-path ,我们可以使用CSS变量轻松调整。现在,我们所要做的就是把它做成动画!

请注意上图中的坐标(用红色表示)。让我们更新这些坐标来创建动画。

clip-path: polygon(
  0% var(--d), /* reverses var(--d) 0% */
  var(--d) 0%, 
  100% 0%, 
  100% calc(100% - var(--d)), 
  calc(100% - var(--d)) 100%, /* reverses 100% calc(100% - var(--d)) */ 
  0% 100% /* reverses var(--d) calc(100% - var(--d)) */
)

诀窍是隐藏该元素的底部和左侧部分,所以剩下的只是一个没有任何深度的矩形元素。

收尾工作

哦,我们完成了!我知道,这有很多棘手的CSS,但(1)我们在正确的网站上做这种事情,(2)目标是通过让不同的CSS属性相互作用,将我们对它们的理解推向新的高度。

你可能会问,既然我们已经结束了这个关于高级CSS悬停效果的小系列,那么下一步该怎么做?我想说的是,下一步是把我们学到的所有知识应用于其他元素,如按钮、菜单项、链接等。由于这个原因,我们把我们的技巧限制在一个标题元素上,保持了相当简单的东西;实际的元素并不重要。带着这些概念去创造、实验和学习新的东西吧!