使用CSS制作文本阴影的酷炫悬停效果教程

486 阅读9分钟

这一次,我们将专注于CSStext-shadow 属性来探索更有趣的悬停效果。你可能在想,给文本添加阴影怎么可能给我们带来很酷的效果,但这里有一个问题:我们实际上不会为这些文本悬停效果制作任何阴影。

text-shadow 但没有文字阴影?

如果不看代码,你们中的许多人都会凭直觉认为,对于每个悬停效果,我们都在复制文本,然后独立地对它们进行动画。现在,如果你检查一下代码,你会发现在HTML中没有一个文本是真正重复的。而且你有没有注意到,在CSS中没有使用content: "text"

这些文本层完全是用text-shadow

悬停效果#1

让我们来分析一下CSS:

.hover-1 {
  line-height: 1.2em;
  color: #0000;
  text-shadow: 
    0 0 #000, 
    0 1.2em #1095c1;
  overflow: hidden;
  transition: .3s;
}
.hover-1:hover {
  text-shadow: 
    0 -1.2em #000, 
    0 0 #1095c1;
}

首先要注意的是,我正在使实际文本的颜色透明(使用#0000 ),以隐藏它。之后,我使用text-shadow 来创建两个阴影,我为每个阴影只定义了两个长度值。这意味着没有模糊半径,使得阴影清晰明了,有效地产生一个具有指定颜色的文本副本。

这就是为什么我能够在介绍中声称这里没有阴影。我们所做的与其说是 "经典 "的阴影,不如说是复制文本的一种简单方法。

Diagram of the start and end of the hover effect.

我们有两个文本层,我们在悬停上移动。如果我们把溢出部分隐藏起来,那么复制的文本就不在视线范围内,而移动使它看起来好像实际的文本被其他文本所取代。这是使本文中所有例子都有效的主要技巧。

让我们来优化我们的代码。我经常使用1.2em 这个值来定义阴影的高度和偏移,这使得它成为CSS自定义属性(我们称之为--h )的理想候选者。

.hover-1 {
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 0 #000, 
    0 var(--h) #1095c1;
  overflow: hidden;
  transition: .3s;
}
.hover-1:hover {
  text-shadow: 
    0 calc(-1 * var(--h)) #000, 
    0 0 #1095c1;
}

我们还可以更进一步,应用更多的calc()-ulations来精简事情,使我们只使用一次text-shadow 。(我们在上一篇文章中也是这样做的)。

.hover-1 {
  --h: 1.2em;   

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 calc(-1*var(--_t, 0em)) #000, 
    0 calc(var(--h) - var(--_t, 0em)) #1095c1;
  overflow: hidden;
  transition: .3s;
}
.hover-1:hover {
  --_t: var(--h);
}

如果你想知道为什么我在--_t 变量上加了一个下划线,这只是我的一个命名惯例,用来区分我们用来控制用户可以更新的效果的变量(如--h )和只用于优化的内部变量,我们不需要改变这些变量(如--_t )。换句话说,下划线是变量名称的一部分,没有特殊意义。

悬停效果#2

对于这一个,我们将动画两个属性:text-shadowbackground 。关于text-shadow ,我们仍然有两个层,就像之前的例子一样,但这一次我们将只移动其中一个,同时在交换过程中使另一个的颜色透明。

.hover-2 {
  /* the height */
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_t, var(--h)) #fff,
    0 0 var(--_c, #000);
  transition: 0.3s;
}
.hover-2:hover {
  --_t: 0;
  --_c: #0000;
}

在悬停时,我们将白色文本层移动到顶部,同时将另一个层的颜色改为透明。对此,我们添加一个background-size 动画,应用于一个渐变。

最后,我们添加overflow: hidden ,使动画只在元素的边界内可见。

.hover-2 {
  /* the height */
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_t,var(--h)) #fff,
    0 0 var(--_c, #000);
  background: 
    linear-gradient(#1095c1 0 0) 
    bottom/100% var(--_d, 0) no-repeat;
  overflow: hidden;
  transition: 0.3s;
}
.hover-2:hover {
  --_d: 100%;
  --_t: 0;
  --_c: #0000;
}

我们在这里所做的是结合CSStext-shadowbackground 属性来创造一个很酷的悬停效果。另外,我们能够使用CSS变量来优化代码。

如果background 语法对你来说很奇怪,我强烈建议你阅读我之前的文章。下一个悬停效果也依赖于我在那篇文章中详述的一个动画。除非你对CSSbackground 的技巧很熟悉,否则我建议在继续这篇文章之前先阅读那篇文章,以了解更多的背景。

我们确实可以使用同样的DRY切换技术,这样我们就只用一个CSS自定义属性,只是在悬停时切换值。

.hover-2 {
  /* the height */
  --h: 1.2em;

  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_i, var(--h)) #fff,
    0 0 rgb(0 0 0 / calc(var(--_i, 1) * 100%) );
  background: 
    linear-gradient(#1095c1 0 0) 
    bottom/100% calc(100% - var(--_i, 1) * 100%) no-repeat;
  overflow: hidden;
  transition: 0.3s;
}
.hover-2:hover {
  --_i: 0;
}

悬停效果#3

这个悬停效果只不过是我们已经做的两个效果的组合:上一篇文章的第二个 悬停效果和本文的第一个悬停效果。

.hover-3 {
  /* the color  */
  --c: #1095c1;
  /* the height */
  --h: 1.2em;

  /* The first hover effect in this article */
  line-height: var(--h);  
  color: #0000;
  overflow: hidden;
  text-shadow: 
    0 calc(-1 * var(--_t, 0em)) var(--c), 
    0 calc(var(--h) - var(--_t, 0em)) #fff;
  /* The second hover effect from the previous article */
  background: 
    linear-gradient(var(--c) 0 0) no-repeat 
    calc(200% - var(--_p, 0%)) 100% / 200% var(--_p, .08em);
  transition: .3s var(--_s, 0s), background-position .3s calc(.3s - var(--_s, 0s));
}
.hover-3:hover {
  --_t: var(--h);
  --_p: 100%;
  --_s: .3s
}

我所做的只是复制和粘贴那些其他例子中的效果,并对变量名称做一些小的调整。当它们结合在一起的时候,就形成了一个整洁的悬停效果!乍一看,这样的效果可能看起来很复杂,很困难,但最终,它只是把两个相对容易的效果合二为一。

如果我们考虑到之前已经做过的优化,用DRY切换变量技术来优化代码也应该是一件容易的事情。

.hover-3 {
  /* the color  */
  --c: #1095c1;
  /* the height */
  --h: 1.2em;

  line-height: var(--h);  
  color: #0000;
  overflow: hidden;
  text-shadow: 
    0 calc(-1 * var(--h) * var(--_i, 0)) var(--c), 
    0 calc(var(--h) * (1 - var(--_i, 0))) #fff;
  background: 
    linear-gradient(var(--c) 0 0) no-repeat
    calc(200% - var(--_i, 0) * 100%) 100% / 200% calc(100% * var(--_i, 0) + .08em);
  transition: .3s calc(var(--_i, 0) * .3s), background-position .3s calc(.3s - calc(var(--_i, 0) * .3s));
}
.hover-3:hover {
  --_i: 1;
}

悬停效果#4

这个悬停效果是对第二个的改进。首先,让我们引入一个 clip-path动画来显示其中一个文本层,然后再移动。

下面是另一个插图,以更好地理解正在发生的事情。

Diagram of the start and end of the text hover.

最初,我们使用inset(0 0 0 0) ,这与overflow: hidden 相似,我们所看到的是实际的文本。在悬停时,我们使用一个等于高度的负值更新第三个值(代表底部偏移),以显示放置在底部的文本层。

从那里,我们可以把这个添加到我们在这篇文章中做的第二个悬停效果,这就是我们得到的。

我们越来越接近了!请注意,我们需要先运行clip-path ,然后再运行其他一切。出于这个原因,我们可以在悬停时为所有的属性添加一个延迟,除了clip-path

transition: 0.4s 0.4s, clip-path 0.4s;

而在鼠标移出时,我们做相反的事情。

transition: 0.4s, clip-path 0.4s 0.4s;

最后是添加一个box-shadow ,创造蓝色矩形的滑动效果。不幸的是,background 无法产生这种效果,因为背景在默认情况下是被剪切到内容区的。同时,box-shadow 可以到内容区之外。

.hover-4 {
  /* the color  */
  --c: #1095c1;
  /* the height */
  --h: 1.2em;
  
  line-height: var(--h);
  color: #0000;
  text-shadow: 
    0 var(--_t, var(--h)) #fff,
    0 0 var(--_c, #000);
  box-shadow: 0 var(--_t, var(--h)) var(--c);
  clip-path: inset(0 0 0 0);
  background: linear-gradient(var(--c) 0 0) 0 var(--_t, var(--h)) no-repeat;
  transition: 0.4s, clip-path 0.4s 0.4s;
}
.hover-4:hover {
  --_t: 0;
  --_c: #0000;
  clip-path: inset(0 0 calc(-1 * var(--h)) 0);
  transition: 0.4s 0.4s, clip-path 0.4s;
}

如果你仔细观察box-shadow ,你会发现它的数值与text-shadow 里面的白色文本层相同。这是符合逻辑的,因为两者需要以同样的方式移动。两者都将滑动到顶部。然后box-shadow 在元素后面,而text-shadow 则在顶部。

接得好!是的,我们正在使用一个不同的技术与background ,产生同样的效果。我们不是让大小从0%100% ,而是让position

如果我们没有在我们的梯度上指定一个尺寸,那么它就会默认占用全部的宽度和高度。由于我们知道我们的元素的高度(--h ),我们可以通过更新位置从0 var(--h)0 0 来创造一个滑动的效果。

.hover-4 {
  /* ... */
  background: linear-gradient(var(--c) 0 0) 0 var(--_t, var(--h)) no-repeat;
}
.hover-4:hover {
  --_t: 0;
}

我们可以使用background-size 动画来获得同样的效果,但我们只是在我们的列表中添加了另一个技巧

在演示中,你也使用了inset(0 0 1px 0)...为什么?

我有时会在这里或那里添加或删除一些像素或百分比,以完善任何看起来不对劲的地方。在这种情况下,底部出现了一条坏线,添加1px ,就可以把它去掉。

DRY开关变量的优化情况如何?

我把这个任务留给你!在这四个悬停效果和前面的文章之后,你应该能够更新代码,使其只使用一个变量。我很想看到你在评论中尝试一下!

轮到你了!

让我分享最后一个悬停效果,它是前一个悬停效果的另一个版本。你能在不看代码的情况下找出它是如何做到的吗?这是个很好的练习,所以不要作弊!

总结

我们看了一些例子,这些例子显示了一个元素和几行CSS就足以在文本元素上创造出一些看起来相当复杂的悬停效果--不需要伪元素!我们甚至能够结合技术来创造悬停效果。我们甚至能够结合各种技术,以少量的努力实现更复杂的动画效果。

如果你有兴趣深入了解本文中的四个text-shadow 悬停效果,请查看我的500个悬停效果集,我正在探索各种不同的技术。