在 Web 中,我们时常会碰到文本淡化的效果。这里所说的文本淡化不是淡入淡出的动画效果,而是文本(或元素)的一种视觉效果,其显著特征是,由清晰逐渐变得不可见,例如容器中的文本,从顶部到底部逐渐由清晰变得不可见,或者越接近容器两侧边缘不可见。
不难发现,上图中右侧命令行文本,从顶部到底部逐渐淡化不可见。接下来,我们来看看,CSS 有哪些方法可以实现这个效果,这些方法各自又有哪些利弊。
钻石段位:叠加层
通常情况下,大多数 Web 开发者都会选择在文本上覆盖一个渐变层。
<div class="container">
<p><!-- 文本内容 --></p>
<div class="gradient"><!-- 渐变层 --></div>
</div>
.container {
position: relative;
overflow: hidden;
.gradient {
position: absolute;
inset: 0;
background: linear-gradient(180deg, transparent 0, oklch(0.14 0 0) 100%);
}
}
你将看到的效果如下:
Demo 地址:codepen.io/airen/full/…
正如你所看到的,通过绝对定位,将 .gradient
元素定位在 .container
容器四边(inset: 0
)。.gradient
只做了一件事情,通过 linear-gradient()
给自己绘制了一个线性渐变背景,顶部是透明色 transparent
,底部是一个黑色 oklch(0.14 0 0)
。
这里有一个小技巧,你可以调整 inset
属性的第一个值(相当于 top
的值)来调整渐变层的高度以使文本淡化更多或更少。此外,你也可以微调渐变中第二个颜色,使文本淡化为任何你想要的颜色(通常情况与文本容器的背景色相同)。
注意,你也可以使用其他渐变,实现不同风格的文本淡化的效果,比如通过径向渐变,实现一个圆形的文本淡化效果。这里就不展示了,有兴趣的同学可以尝试一下。另外,示例中颜色应用了 oklch()
函数来描述,这是现代 CSS 中描述颜色的新函数,与其相似的还有一个 oklab()
,可以使用它们给 Web 定义高清颜色。如果你感兴趣的话,可以移步阅读《CSS 中的 OKLCH 和 OKLAB》一文。
另一个技巧是,你还可以使用 CSS 的伪元素 ::before
或 ::after
来替代 .gradient
元素,并且使用 CSS Grid 布局,通过网格区域来放置渐变层,如此一来,渐变层就不再需要应用绝对定位:
<div class="wrapper">
<div class="container">
<div class="content">
<p><!-- 淡化文本都放在 content 容器中 --></p>
</div>
</div>
</div>
.wrapper {
container-type: inline-size;
min-width: 50vw;
}
.container {
overflow: hidden;
display: grid;
.content {
grid-area: 1 / 1 / -1 / -1;
}
&::after {
content: "";
grid-area: 1 / 1 / -1 / -1;
width: 100%;
height: 100%;
z-index: 2;
background: linear-gradient(180deg, transparent 0, oklch(0.14 0 0) 100%);
align-self: end;
}
}
Demo 地址:codepen.io/airen/full/…
上面这个示例还是应用到了一些新知识的,比如 CSS 的容器查询,网格布局中的网格放置,网格对齐方式等。尤其需要注意伪元素 ::after
的 height
,示例应用的是 100%
,需要想办法使其有参考物,否则计算出来的高度将会是 0
。这个现象应该有不少同学碰到过。
星耀段位:background-clip
我想你可能已经发现了,使用叠加层实现的文本淡化效果,具有两个明显的缺点:
-
叠加层(渐变层)后面的文本不可选,这对于 Web 可访问性来说是致命的,如果文本中带有跳转的链接等,那将失去原本的作用
-
该效果仅适用于纯色背
第一个问题很容易解决,你可以在叠加层上设置 user-select
和 pointer-events
属性:
.container::after {
user-select: none;
pointer-events: none;
}
如果要解决第二个问题,即在非纯色背景(如图片或渐变背景)实现文本淡化的效果,则需要采用不同的方法。为了使其在这种情况下起作用,我们实际上需要使文本淡化,而不是使其看起来淡化。
在 CSS 中有多种不同的方法可以实现该效果,其中之一就是渐变文本。
<div class="container">
<!-- 容器带有一个渐变色 -->
<div class="content">
<!-- 需要淡化的文本 -->
<p></p>
</div>
</div>
.container {
background: linear-gradient(to bottom, #ad3e1b, #ff0770);
.content {
background: linear-gradient(to bottom, white, transparent);
color: transparent;
background-clip: text;
}
}
Demo 地址:codepen.io/airen/full/…
使用这种方法,有一个细节需要注意,文本颜色 color
需要显式设置为透明色,例如 color: transparent
,并且要将 background-clip
设置为 text
,只有这样才能实现渐变色填充文本的效果。这种方法是真正实现文本淡化的效果。你也可以通过调整 background-size
和 background-position
来调整文本淡化的位置和大小。
另一个需要注意的是,文本渐变色需要从文本颜色到透明。请注意,文本如何在整个渐变中均匀淡化,并且每个单词仍然可选择,因为我们没有叠加任何东西在文本之上。
当然,这种技术也是有它自身的缺陷。由于文本现在是透明的(color: transparent
),它采用的是渐变填充。如果你的内容对于链接或其他元素(比如表情符)具有不同的颜色,那么这些颜色将被替换(表情符颜色被替换)或不会淡化(链接颜色不会被淡化):
Demo 地址:codepen.io/airen/full/…
如果你希望保留这些颜色并淡化内容,那就得使用更高级的技术。
王者段位:Masking
CSS 遮罩 mask 技术就是一种更高级的技术。我们可以将应用于叠加层的渐变用于 mask-image
,作为遮罩层,类似于在图形编辑器中的工作方式。
通常,遮罩图像的透明通道(Alpha)用于确定元素的哪些部分可见,哪些部分不可见,但你可以将 mask-mode
设置为 luminance
并使用黑白蒙版。但是,出于我们的目的,透明通道(Alpha)就足够了。
<div class="container">
<!-- 容器带有一个渐变色 -->
<div class="content">
<!-- 需要淡化的文本 -->
<p></p>
</div>
</div>
.container {
background: linear-gradient(to bottom, #ad3e1b, #ff0770);
.content {
mask-image: linear-gradient(to bottom, white, transparent);
}
}
Demo 地址:codepen.io/airen/full/…
同样的,你可以通过调整 mask-size
和 mask-position
来调整遮罩层的位置和大小,得到不同的淡化效果。当然,改变遮罩层效果亦是如此!
如果你从未接触过 CSS 遮罩相关的知识,或者想更进一步了解该技术,个人建议你移步阅读《CSS 的 Clipping 和 Masking》!
小结
正如前面所述,在 CSS 中有多种方式可以实现文本淡化的效果,而且这种效果也可以应用于 Web 中很多场景中。比如我在《防御式 CSS 精讲》中《如何提高图片上文本的可读性?》课程中所阐述的内容,也可以应用到这些技术。
如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程: