CSS Tips:CSS 实现文本淡化效果的不同姿势

684 阅读6分钟

在 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 的容器查询网格布局中的网格放置网格对齐方式等。尤其需要注意伪元素 ::afterheight ,示例应用的是 100% ,需要想办法使其有参考物,否则计算出来的高度将会是 0 。这个现象应该有不少同学碰到过。

有关于 CSS 网格布局更多的介绍,可以移步阅读《现代 Web 布局》中的 CSS 网格布局

星耀段位:background-clip

我想你可能已经发现了,使用叠加层实现的文本淡化效果,具有两个明显的缺点:

  • 叠加层(渐变层)后面的文本不可选,这对于 Web 可访问性来说是致命的,如果文本中带有跳转的链接等,那将失去原本的作用

  • 该效果仅适用于纯色背

第一个问题很容易解决,你可以在叠加层上设置 user-selectpointer-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-sizebackground-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-sizemask-position 来调整遮罩层的位置和大小,得到不同的淡化效果。当然,改变遮罩层效果亦是如此!

如果你从未接触过 CSS 遮罩相关的知识,或者想更进一步了解该技术,个人建议你移步阅读《CSS 的 Clipping 和 Masking》!

小结

正如前面所述,在 CSS 中有多种方式可以实现文本淡化的效果,而且这种效果也可以应用于 Web 中很多场景中。比如我在《防御式 CSS 精讲》中《如何提高图片上文本的可读性?》课程中所阐述的内容,也可以应用到这些技术。


damo.gif

如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程: