在我的 上一篇文章 中,我们了解了如何使用 CSS background
属性创建酷炫的悬停效果。这一次,我们将重点关注 CSS text-shadow
属性,以探索更多有趣的效果。您可能想知道,在文本中添加阴影如何才能产生酷炫的效果,但关键在于:我们实际上不会为这些文本悬停效果创建任何阴影。
酷炫的悬停效果系列
- 使用背景属性创建酷炫的悬停效果
- 使用 CSS 文本阴影创建酷炫的悬停效果(您就在这里!)
- 使用背景裁剪、蒙版和 3D 创建酷炫的悬停效果
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
创建了两个阴影,其中我为每个阴影仅定义了两个长度值。这意味着没有模糊半径,从而形成了一个清晰锐利的阴影,有效地以指定颜色复制了文本。
这就是我为什么在引言中声称这里没有阴影的原因。我们所做的是比“经典”阴影更简单的文本复制方法。

我们有两个文本层,我们在悬停时移动它们。如果我们隐藏溢出,则复制的文本将不可见,而移动则使它看起来像是实际文本被其他文本替换了。这是本文所有示例都起作用的主要技巧。
让我们优化我们的代码。我经常使用值 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()
计算,将代码简化为只使用一次 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
),我们不需要更改(例如 --_t
)。换句话说,下划线是变量名称的一部分,没有特殊含义。
我们还可以更新代码以获得相反的效果,即复制的文本从顶部滑入。
我们只对 text-shadow
属性进行了一些小的更新——我们没有触碰其他任何内容!
悬停效果 #2
对于这个效果,我们将对两个属性进行动画处理:text-shadow
和 background
。关于 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;
}
我们在这里所做的是将 CSS text-shadow
和 background
属性结合起来,以创建一个酷炫的悬停效果。此外,我们能够使用 CSS 变量来优化代码。
如果您觉得 background
语法很奇怪,我强烈建议您阅读 我之前的文章。下一个悬停效果也依赖于我在那篇文章中详细介绍的动画。如果您不熟悉 CSS background
的技巧,建议您阅读那篇文章,然后再继续阅读本文,以便获得更多上下文。
在上一篇文章中,您向我们展示了如何只使用一个变量来创建悬停效果——我们可以在此处这样做吗?
当然可以!我们确实可以应用 相同的 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
动画,以便在文本层移动之前显示它。
以下是另一个插图,以便更好地理解正在发生的事情。

最初,我们使用 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 个悬停效果,我正在探索各种不同的技术。