Skip to content

文本叠加在图片上是 Web 中常见的一种 UI 设计效果,只不过在某些情况之下,比如图片加载失败、图片与文本颜色对比度等,会造成叠加在图片上的文本变得难于阅读,比如:

img

图片和文本颜色接近时,造成叠加在图片上的文本难于阅读:

img

针对这些场景,不管是 Web 设计师还是 Web 开发者,都应该有一些解决方案,使叠加在图片上的文本变得更易于阅读。在这节课程中,我们将一起来聊聊,在 Web 开发过程中,有哪些方法可以让图片上的文本变得易读。

设计角度:文本叠加在图片上的解决方案

@Suleiman Ali Shakir 从设计的角度为大家提供了一些方法。

使用围网(Scrim)

Scrim 是一个半透明的渐变层,可以帮助文本在背景下显得更易于阅读。

Scrim 是一个从纯色到透明的渐变,位于文本的后面。正如 @Addy Osmani 在 Twitter 所说,在图片和文本之间添加一个渐变层:

img

更多的时候,使用 Scrim 设计效果时,会把透明度的百分比留给你来决定,一般情况之下,从 40% 的黑色到透明是一个最佳的方案。它不会太明显,也不会干扰图片。平滑地淡化,给文本标签所需要的对比度,使其可读:

img

覆盖整个图片透明颜色

这个有点类似 Scrim 的解决方案,但不是渐变,而是在整个图片上应用带有一定透明度的纯色,比如带有 40% 透明度的纯黑色。

img

采用这种设计解决方案的话,说明文本比图片更重要

颜色叠加

在图片上叠加一个不是黑色或白色的颜色,让图片变暗或变亮。在图片上设置颜色叠加是中和图片的一种解决方案 。它使图像变得更单调:

img

柔软的渐变

它和 Scrim 是相同的,也是采用渐变叠加层,不同之处在于这种渐变是一种柔软的渐变色。当你使用这种渐变时,不要使用视觉上有冲突的颜色,选择能和谐相处的颜色。另外,要正确使用这种渐变,有一个条件,那就是文本应该有足够的对比度

img

你可以使用一些在线的工具,让你设计渐变色变得更容易,比如 CoolorsAdobe 的 Kuler。它们可以帮助你生成配合良好的颜色对(渐变色)。

半透明的图片

这种技术包括在纯色背景下使用半透明的图片。它有助于“平息”嘈杂的背景,使文本能够脱颖而出。这种技术由三个层次组成(从底部开始):

  • 纯色的底部;
  • 带有一定透明度图片的中间层(一般是 40% 透明度的图片);
  • 顶部的文本层。

img

高斯模糊

使用高期模糊来软化图片,让文本变得易于阅读。这种技术是通过减少图片噪音和细节来平滑图片。

img

文本高亮

给图片上的文本添加一个高亮的背景颜色。这种效果模仿了传统的在纸上突出文字的方式。而且这种效果对于小文本位于大的背景时,效果会特别的好。记住,高光色不一定是黑色。比如下图中右边的例子借用了图片中的主色调。就为文本创造了更高的归属感。

img

图片置灰

很多时候可以改变图片,而不是改变文本。比如把图片置灰,也可以让图片上的文本变得易于阅读。

img

颜色和定位

有的时候,Web 上的图片看上去都是一样的。比如说,一个分类页面使用一个恒定的标题图片来分类。在这种情下,除了使用代表分类的图片之外,还可以使用一些文本样式来区分。文本样式可以是字体、大小、颜色、甚至是文本位置。如下图所示:

img

开发角度:文本叠加在图片上的解决方案

上面是所列出的是从设计角度让文本更易于阅读的方案,不管是上面哪种设计方案,它们都有一个共性,即这种 UI 效果从底部到顶部有三个层级:

  • 底部:图片;
  • 中间层:隔离层;
  • 顶部:文本。

隔离层可以有很多种效果,比如说渐变色、纯色等:

img

对于 Web 开发者而言,借助设计师提供的相关理念,在开发的过程中,同样可以有不同的解决方案。

  • 带渐变效果的叠加层;
  • 带有透明度的纯色叠加层;
  • 纯色和渐变混合的叠加层;
  • 半透明的图片;
  • 高斯模糊的图片;
  • 图片置灰;
  • 给叠加文本添加阴影;
  • 文本高亮。

img

拿一个卡片组件为例,你可能需要这样一个 HTML 结构:

HTML
<figure class="card">
    <img src="./elephant-660-480.jpg" alt="Elephant at sunset">
    <figcaption>An elephant at sunset</figcaption>
</figure>

我们使用 CSS Grid 布局技术来实现在图片上叠加文本:

CSS
figure {
    display: grid;
}

figure > *{
    grid-area: 1 / 1 / -1 / -1;
}

figcaption {
    align-self: end;
}

img

Demo 地址:https://codepen.io/airen/full/oNPEMyq

注意,示例没有使用额外标签元素来当作中间层。因为,在 CSS 中,我们可以使用伪元素 ::before::after 来当作中间层(如果需要用到中间层的话):

img

CSS
display: grid;
}

figure > *{
    grid-area: 1 / 1 / -1 / -1;
}

figcaption {
    align-self: end;
    z-index: 3;
}

figure::before {
    content: "";
    grid-area: 1 / 1 / -1 / -1/
    z-index: 2;
}

img

Demo 地址:https://codepen.io/airen/full/VwGQGag

上面我们介绍了 CSS 如何实现叠加布局。接下来,我们看看如何能让叠加在图片上的文本变得更易于阅读。

渐变的叠加层

从 Web 设计师角度来看,叠加层可以是一个渐变层,它可以是 Scrim 或柔和的渐变。也就是说,Web 开发者可以考虑中间的叠加层使用 CSS 的渐变来构建。相对而言,它(渐变层)也是最常见的解决方案,使文本在图片上更清晰。

我们可以考虑在叠加层使用 Scrim 设计效果,即一个带有 40% 透明度黑色到透明的渐变

CSS
figure::before {
    background-image: linear(to top, rgb(0 0 0 / 40%), rgb(0 0 0 / 0));
}

img

Demo 地址: https://codepen.io/airen/full/rNZJoxG

第一眼看上去,你可能会认为渐变(Scrim)很好,但并不代表所有场景都是如此。我们复制多个卡片,图片将会不一样:

img

Demo 地址:https://codepen.io/airen/full/wvEyRyW

你可能已经发现了,不是所有卡片上白色文本和图片之间的对比度都是很清晰的,这样的渐变并不会让所用用户易读。

造成这种现象的主要原因是,渐变应该在垂直方向上覆盖更多的空间,所以它的高度需要更大。让渐变与内容的大小相等,并不是所有情况下都是行得通的。为了解决这个问题,可以通过 background-size 来改变渐变的高度:

CSS
figure::before {
    background-image: linear-gradient(to top, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0));
    background-size: 100% 42.5%;
    background-position: left bottom;
    background-repeat: no-repeat;
}

img

Demo 地址:https://codepen.io/airen/full/zYJRymJ

其实,只是改变 background-size 还不是最佳的方案,更好的方案是使用 CSS 比较函数(比如 min()max() clamp() 等)调整渐变颜色位置。比如:

CSS
.element { 
    background: linear-gradient(to top, #000 0, transparent max(20%, 20vw)); 
}

img

注意,CSS 比较函数 min()max()clamp() 相关的知识已超出这节课的范畴,如果你感兴趣的话,可以阅读《如何构建响应式 UI》一文。

max() 函数运用到 linear-gradient 上面:

CSS
figure::before {
    background-image: linear-gradient(to top, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0) max(20%, 20vw));
}

img

Demo 地址: https://codepen.io/airen/full/JjapxNj

除此之外,还可以将 max() 中的视窗单位 vw 换成容器查询单位,比如 cqh 。渐变中颜色停止位置使用容器查询单位,渐变的颜色停止位置可以根据容器的高度来调整:

CSS
figure::before {
    background-image: linear-gradient(to top, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0) max(20%, 40cqh));
}

img

Demo 地址:https://codepen.io/airen/full/wvEyRyW

除了上面介绍的渐变之外,还可以使用缓动渐变

img

CSS
figure::before {
    background-image: linear-gradient(
        to top,
        hsla(0, 0%, 0%, 0.62) 0%,
        hsla(0, 0%, 0%, 0.614) 7.5%,
        hsla(0, 0%, 0%, 0.596) 13.5%,
        hsla(0, 0%, 0%, 0.569) 18.2%,
        hsla(0, 0%, 0%, 0.533) 22%,
        hsla(0, 0%, 0%, 0.49) 25.3%,
        hsla(0, 0%, 0%, 0.441) 28.3%,
        hsla(0, 0%, 0%, 0.388) 31.4%,
        hsla(0, 0%, 0%, 0.333) 35%,
        hsla(0, 0%, 0%, 0.277) 39.3%,
        hsla(0, 0%, 0%, 0.221) 44.7%,
        hsla(0, 0%, 0%, 0.167) 51.6%,
        hsla(0, 0%, 0%, 0.117) 60.2%,
        hsla(0, 0%, 0%, 0.071) 70.9%,
        hsla(0, 0%, 0%, 0.032) 84.1%,
        hsla(0, 0%, 0%, 0) 100%
    );
}

img

Demo 地址:https://codepen.io/airen/full/poOLbYg

上面示例中缓动渐变是使用工具生成出来的,不过未来一定可以使用原生的缓动渐变:

CSS
figure::before {
   background-image: linear-gradient(
        to top,
        hsla(330, 29%, 0%, 0.62),
        cubic-bezier(0.42, 0, 0.13, 0.78),
        hsla(210, 0%, 100%, 0)
    );
};

如果你现在就想在生产环境中使用缓动渐变的话,你可以使用上面的工具来帮助你生成缓动渐变,或者使用 PostCSS 插件帮你自动编译。

上面示例有一个共性,都是从一个带有 40% 透明度的黑色颜色自底向顶透明地渐变。正如 @Suleiman Ali Shakir 所说,我们还可以使用一些更柔和的渐变,比如像 Hypercolorconic.css 生成的渐变:

img

不过,叠加层使用这种渐变效果,需要给叠加层设置一定的透明度,比如 opacity: .65 ,只有这样才能看到叠加层底下的图片:

CSS
figure::before {
    background-image:conic-gradient(
        from 90deg at 40% -25%, 
        #ffd700, 
        #f79d03, 
        #ee6907, 
        #e6390a, 
        #de0d0d, 
        #d61039, 
        #cf1261, 
        #c71585, 
        #cf1261, 
        #d61039, 
        #de0d0d, 
        #ee6907, 
        #f79d03, 
        #ffd700, 
        #ffd700, 
        #ffd700
    );
    opacity: .65;
}

img

Demo 地址:https://codepen.io/airen/full/bGxvwEN

除此之外,你还可以根据自己的设计需求来调整叠加层的渐变样式,比如改变渐变方向、使用径向渐变等。

带有透明度的纯色叠加层

这个方案可以说和渐变的叠加层是同一种技术方案,只不过不同的是,它是一个带有一定透明度的纯色叠加层

CSS
figure::before {
    background-color: rgb(0 0 0 / .6);
}

它的优势是,你可以使用任何一种你喜欢的颜色:

img

Demo 地址:https://codepen.io/airen/full/WNgzGZx

这种方案也有其不足之处,会使底层的图片不够清晰。

颜色和渐变混合的叠回层

这种方案指的是,叠加层是一个渐变层,又是一个带有一定透明度的纯色层。简单地说,就是将渐变层和带有一定透明度的纯色层混合在一起:

CSS
figure::before {
    background-color: rgb(0 0 0 / 0.4);
    background-image: linear-gradient(to top, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0) max(20%, 40cqh));
}

img

Demo 地址:https://codepen.io/airen/full/XWPEjwP

相比之下,渐变叠加层的效果会更好一些。

带一定透明度的图片

这个方案和前面三种方案略有不同。在图片和内容之间并没有新增一个叠加层,而是考虑在图片底部添加一个纯色的颜色层:

  • 顶层:内容层;
  • 中间层:带有一定透明度的图片;
  • 底层:纯色层。
CSS
figure {
    background-color: rgb(0 0 0);
}

figure img {
    opacity: .6;
}

你也可以使用伪元素 ::before::after 来模拟纯色的底层:

CSS
figure::after {
    background-color: rgb(0 0 0);
    z-index: -1;
}

figure img {
    opacity: .6;
}

img

Demo 地址:https://codepen.io/airen/full/vYzRyOO

图片高斯模糊

除了改变图片透明度之外,还可以改变图片的渲染效果。比如带有高斯模糊或磨砂玻璃效果的图片:

CSS
figure::before {
    background-color: rgb(255 255  255 / 0.06);
    backdrop-filter: blur(5px);
}

img

Demo 地址:https://codepen.io/airen/full/zYJWoBe

这种效果,还可以借助 CSS 的自定义属性,让你的代码变得更灵活一些:

CSS
.adaptive--glass {
    --glass-lightness: 100%;
    --blure: 40px;
    
    background-color: hsl(0 0% var(--glass-lightness) / 50%);
    backdrop-filter: blur(var(--blure));
}

@media (prefers-color-scheme: dark) {
    .adaptive--glass {
        --glass-lightness: 0%;
    }
}

注意,示例中代码使用了 CSS 媒体查询的 prefers-color-scheme 条件查询,可以让你的图片根据用户的喜好调整相应的亮度。如果设备设置的是亮色模式下,那么 hsl() 的亮度是 100% ;如果设备设置的暗色模式下,那么 hsl() 的高度是 0%

CSS 媒体查询中还有其他的条件查询规则,可以更好地帮助你根据用户的喜好来调整样式,在这里不做详细阐述,因为它已超出这节课的范畴,如果你感兴趣的话,可以点击这里获取相关教程,或者搜索相关的关键词。

图片置灰

图片置灰的方案和带有高斯模糊的图片方案是相似的。在 CSS 中,我们可以有多种方式来改变图片的效果:

img

图片截取于 https://bennettfeely.com/image-effects/

如上图所示,使用 CSS 的 filtermix-blend-mode 可以构建出很多不同的图片效果,其中置灰图片就是最简单的一种。只需要使用 filter 即可:

CSS
figure img {
    filter: grayscale(1);
}

img

Demo 地址:https://codepen.io/airen/full/VwGXmya

你可能已经发现了,图片置灰的情况下,也有可能会让文本不易于阅读,比如文本是白色时。

当然,还可以像 @Ahmad Shadeed 的 《Blending Modes In CSS》一文中所介绍的那样,使用 CSS 的 mix-blend-modebackground-blend-mode 来改变图片的渲染风格,使叠加在图片上的文本变得更清晰。

img

或者直接使用 @Una 提供colofilter.css 改变图片风格:

img

给文本添加阴影

我们除了设置图片或叠加层效果之外,还可以给叠加的文本添加效果,比如给文本运用 text-shadow 效果:

CSS
figcaption {
    text-shadow: 0 2px 3px rgba(0, 0, 0, 0.3);
}

img

Demo 地址:https://codepen.io/airen/full/mdGxRmx

文本高亮

文本高亮就是在叠加文本上添加一个高亮的纯色,比如:

CSS
figcaption {
    background-color: rgb(0 0 0);
}

img

Demo 地址:https://codepen.io/airen/full/mdGxRML

你也可以调整其背景颜色的透明度:

CSS
figcaption {
    background-color: rgb(0 0 0 / .6);
}

img

Demo 地址:https://codepen.io/airen/full/YzOaNEe

给文本选择一个具有可访问性的叠加颜色

文本叠加在图片时添加一个叠加层(渐变、纯色或图片高斯模糊等),主要是为了解决文本可读性问题(即使是这样,也并不代表你添加的叠加层就能让文本易于阅读)。庆幸的是,我们可以使用浏览器一些工具,比如 Firefox,对渐变进行色彩对比测试。它能帮你测量出最小和最大的对比度:

img

除了使用上面这样的测试工具之外,还可以使用 @Yaphi 写的工具,可以计算出理想的不透明度,以便使对比度符合 WCAG 标准

img

在线地址:https://codepen.io/yaphi1/full/oNbEqGV

让加载失败的图片样式更美观一些

前面有提到过,<img> 加载图片时,可能会因为某些原因加载失败。一旦图片加载失败,除了会影响图片上文本的可读性之外,它的外观也是很丑的。有可能直接拉低了 Web 的颜值。

img

其实,你可以使用 @Ire Aderinokun 的《Styling Broken Images》教程所介绍的方案,使用 CSS 的伪元素 ::before::after 让加载失败的图片在浏览器呈现上变得更美观:

CSS
img { 
    /* Same as first example */
    min-height: 50px;
}

img::before,
img::after {
    position: absolute;
    width: 100%;
    left: 0;

}

img::before { 
    content: " ";
    top: -10px;
    height: calc(100% + 10px);
    background-color: rgb(230, 230, 230);
    border: 2px dotted rgb(200, 200, 200);
    border-radius: 5px;
}

img::after { 
    content: "\f127" " Broken Image of " attr(alt);
    font-size: 16px;
    font-style: normal;
    font-family: FontAwesome;
    color: rgb(100, 100, 100);
    top: 5px;
    text-align: center;
}

img

Demo 地址:https://codepen.io/airen/full/qBMorWx

小结

文本叠加在图片上时,不管如何设计,总是无法避免两者颜色相似度过高,降低文本的清晰度问题,甚至有的时候让人无法看清楚文本,这会给用户带来很不好的体验,甚至会造成用户的流失。

在这节课中,我们分别从设计和开发的两个角度阐述了如何让叠加在图片上的文本提高清晰度和可读性。从前面的内容中不难获知,有很多种方案可以做到,但每种不同的方案有着自己的利弊,要么图片变得不清晰,要么文本清晰度被降低。但相对而言,比你不做任何处理效果要好得多,而且所需代码也并不多。

当然,这些方案都不是什么很了不起的技巧,但重点是,我们依旧要有一个“万一”的思想,万一图片加载失败呢?万一输出的图片和文本颜色太接近呢,等等…… 为了防止这些情况出现,我们就要提供一个以防万一的解决方案,比如:

  • 文本和图片之间添加一个渐变层;
  • 文本和图片之间添加一个带透明度的颜色层;
  • 给文本添加阴影;
  • 让文本变得高亮。