处理图片上文字效果的几种姿势
你可能时常会在平时的开发中碰到文字显示在图片上的 UI 效果。在某些情况下,因为图片的不同,文本放置在图片上会让文本变得难于易读。针对于这种情况,不管是设计师还是Web开发者,都会有一些解决方案,比如在图片和文本之间添加一个渐变覆盖,或者有一个有色的背景,或给文本添加阴影等让文本变得更易于阅读。在这篇文章中,和大家一起来讨论这些解决方案,如果你感兴趣的话,请继续往下阅读。
叠加在图片上文本的缺陷
文本在图片上方是 Web 中常见的一种 UI 组件,比如:
正如上图所示,这种 UI 效果已是 Web 中的一种流行设计。但这种设计也有一定的牺牲:
- 图片的清晰度
- 文本的可读性
可读性是指读者能够理解书面文字的难易程度。它是衡量读者如何轻松地将单个字母或字符区分开来 —— 维基百科
也就是说,叠加文本会妨碍完全观看图片。此外,你的文本可能无法阅读。
针对于这种局限(或缺陷),我们有相应的技术手段可以来让叠加在图片上的文本变得易读。
除了该技术,还有其他一些技术方案。
设计角度:文本叠加解决方案
@Suleiman Ali Shakir 从设计的角度为大家提供了一些使叠加在图片上的文本变得易于阅读。
使用围网(Scrim)
Scrim 是一个半透明的渐变层,可以帮助文本在背景下显得更易于阅读。
Scrim 是一个从纯色到透明的渐变,位于文本的后面。正如 @Addy Osmani在Twitter所说,在图片和文本之间添加一个渐变层:
更多的时候,使用 Scrim 设计效果时,会把透明度的百分比留给你来决定,一般情况之下,从 40%
的黑色到透明是一个最佳的方案。它不会太明显,也不会干扰图片。它平滑地淡化,给文本标签以它所需要的对比度,使其可读:
覆盖整个图片透明颜色
这个有点类似 Scrim 的解决方案,但不是渐变,而是在整个图片上应用带有一定透明度的纯色,比如带有 40%
透明度的纯黑色。
采用这种设计解决方案的话,说明文本比图片更重要。
颜色叠加
使用一个不是黑色或白色来叠加在图片上,让图片变暗或变亮。在图片上设置颜色叠加是中和图片的一种解决方案。它让图像变得更单调:
柔软的渐变
它和 Scrim 是相同的,也是采用渐变叠加层,不同之处是这种渐变是一种柔软的渐变色。当你使用这种渐变时,不要使用视觉上有冲突的颜色。选择能和谐相处的颜色。另外,要正确使用这种渐变,有一个有条件,那就是文本应该有足够的对比度。
你可以使用一些在线的工具,让你设计渐变色变得更容易,比如 Coolors 和 Adobe 的 Kuler。它们可以帮助你生成配合良好的颜色对(渐变色)。
半透明的图片
这种技术包括在纯色背景下使用半透明的图片。它有助于“平息”嘈杂的背景,使文本能够脱颖而出。这种技术由三个层次组成(从底部开始):
- 纯色的底部
- 带有一定透明度图片的中间层(一般是
40%
透明度的图片) - 顶部的文本层
高斯模糊
使用高期模糊来软化图片,让文本为得易于阅读。这种技术是通过减少图片噪音和细节来平滑图片。
文本高亮
给图片上的文本添加一个高亮的背景颜色。这种效果模仿了传统的在纸上突出文字的方式。而且这种效果对于设计有最小的文字和宽敞的背景时,效果会特别的好。记住,高光色不一定是黑色。比如下图中右边的例子借用了图片中的主色调。就为图片创造了更高的归属感。
图片置灰
很多时候可以改变图片,而不是改变文本。比如把图片置灰,也可以达到让图片上的文本变得易于阅读。
颜色和定位
有时,无论如何,图片都是一样的。比如说,一个分类页面将使用一个恒定的标题图片来描绘其分类。在这种情况下,你知道应该期待什么图片。你可以使用这些信息来设计你的文本。这可以是字体、大小、颜色,甚至是文字的定位。
开发角度:文本叠加的解决方案
上面是所列出的是从设计角度来解决文本和图片叠加时让文本更易于阅读的方案。不管上面哪种设计方案,他们都有一个共性,即这种 UI 效果从度部到顶部有三个层级:
- 底部:图片
- 中间层:隔离层
- 顶部:文本
隔离层可以有很多种效果,比如说渐变色、纯色等:
接下来我们从Web开发的角度来看,如何让文本在图片上叠加时,文本更易于阅读。
先来看 HTML 的结构,一般情况下,实现这种 UI 效果,其结构大多像下面这样:
<div class="card">
<div class="card__content">
<h2>Card Title</h2>
<p>Some des will go here and I need it to wrap into lines</p>
</div>
<div class="card__thumb">
<img src="https://picsum.photos/966/358?random=1" width="966" height="358" alt="" />
</div>
</div>
在上面的结构中,我们看到了顶部的文本内容层和底部的图片层,而中间的“叠加层”一般采用的是 CSS 的伪元素 ::before
或 ::after
来构建。有关于这方面更多的介绍,可以阅读:
特别声明,叠加层可能不是必备的,可以将一些效果直接运用在 .card__content
上。也就是说,在实现叠加层时,我们有两种选择:
- 为叠加层单独使用一个元素(伪元素或一个空的
<div>
) - 将叠加层效果(比如渐变)作为背景图片应用在文本容器上,比如
.card__content
我们来看看代码:
/* 方案一 */
.card {
position: relative;
}
.card__content {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
color: #fff;
background-image: linear-gradient(to top, rgb(0 0 0 / .4), rgb(0 0 0 / 0));
z-index: 2;
}
/* 方案二 */
.card {
position: relative;
}
.card::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-image: linear-gradient(to top, rgb(0 0 0 / .4), rgb(0 0 0 / 0));
z-index: 2;
}
.card__content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 3;
}
上面示例是使用了伪元素::after
来构建的叠加层。我们还可以直接把渐变放置在 .card__content
元素上:
上面两个示例,都是通过 CSS 的 position
和 z-index
来让文本和图片叠加在一起,即为了将内容放置在图片上,需要在 .card__content
使用绝对定位,并且显式指定 z-index
的值更大,让它在图片上。
如果你接触过 CSS Grid 布局的话,实现上面的效果就不再需要 position: absolute
。只需要把 .card
设置成网格容器(display: grid
),并且不需要显式设置任何的网格轨道:
.card {
display: grid;
}
.card__content {
color: #fff;
display: flex;
flex-direction: column;
justify-content: flex-end;
background-image: linear-gradient(to top, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0));
}
默认情况之下,CSS Grid 会根据内容自动创建行。在网格容器(.card
)中,我们有两个主要元素(.card
的直接子元素.card__content
和 .card__thumb
),所以会自动创建一个两行一列的网格。为了使内容与图片叠加在一起,我们需要把书它们都放在同一个网格区域。
.card__thumb,
.card__content {
grid-column: 1/2;
grid-row: 1/2;
}
.card__content {
z-index: 2;
}
我们也可以使用 grid-column
和 grid-row
的简写属性 grid-area
:
.card__thumb,
.card__content {
grid-area: 1/2;
}
最后,我们还可以使用 grid-area: 1 / -1
。其中 -1
代表网格中的最后一列和最后一行,所以它总是会跨越列或行的末端。
.card__thumb,
.card__content {
grid-area: 1 / -1;
}
最终效果如下:
上面我们探讨的是层级叠加在一起的技术,接下来,我们来看看叠加层的效果。
渐变的叠加层
前面说过,从设计师的角度来看,叠加层有多种方式是使用渐变来实现的,比如 Scrim和柔和的渐变等。比如 Scrim 的叠加层,是一个带有 40%
透明度黑色到透明的渐变:
.card__content {
background-image: linear-gradient(to top, rgb(0 0 0 / 0.4), rgb(0 0 0 / 0));
}
从第一眼看上去,你可能会认为渐变(Scrim)很好,但这并不一定是正确的。我们来更换不同的图片:
正如上面示例所示,白色文本和图片之间的对比度并总是很清晰:
这对于某些用户来说可能是可读的,但使用这样的渐变层是一个巨大的错误,因为它不会让所用用户易读。造成这种现象的主要原因是,渐变应该在垂直方向上覆盖更多的空间,所以它的高度需要更大。让渐变与内容的大小相等,并不是所有情况下都是行得通的。为了解决这个问题,可以通过background-size
来改变渐变的高度:
.card__content {
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;
}
记得,我曾在 《图解CSS: CSS渐变》 一文中介绍过另一种渐变效果,即 缓动渐变:
我们可以把这种缓动渐变运用到叠加层上:
.card__content {
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%
);
}
我们来看线性渐变和缓动线性渐变两者的差异:
上面示例中缓动渐变是使用工具生成出来的,不过未来有一定可以使用原生的缓动渐变:
#future {
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 所说,我们还可以使用一些更柔和的渐变,比如像 Hypercolor 和 conic.css 生成的渐变:
来看一个简单地示例:
.card__content {
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:.6
:
除此之外,还可以改变渐变的方向,比如换成水平的渐变:
.card__content {
background: linear-gradient(
to right,
hsl(0, 0%, 0%) 0%,
hsla(0, 0%, 0%, 0.964) 7.4%,
hsla(0, 0%, 0%, 0.918) 15.3%,
hsla(0, 0%, 0%, 0.862) 23.4%,
hsla(0, 0%, 0%, 0.799) 31.6%,
hsla(0, 0%, 0%, 0.73) 39.9%,
hsla(0, 0%, 0%, 0.655) 48.2%,
hsla(0, 0%, 0%, 0.577) 56.2%,
hsla(0, 0%, 0%, 0.497) 64%,
hsla(0, 0%, 0%, 0.417) 71.3%,
hsla(0, 0%, 0%, 0.337) 78.1%,
hsla(0, 0%, 0%, 0.259) 84.2%,
hsla(0, 0%, 0%, 0.186) 89.6%,
hsla(0, 0%, 0%, 0.117) 94.1%,
hsla(0, 0%, 0%, 0.054) 97.6%,
hsla(0, 0%, 0%, 0) 100%
);
}
当然,也可以把线性渐变换成径向渐变或锥形渐变:
.card__content {
background-image: radial-gradient(
ellipse 100% 100% at right center,
transparent 80%,
#000
);
}
纯色叠加层
除了渐变叠加层之外,很多设计是一个带有一定透明度的叠加层。
.card__content {
background-color: rgb(0 0 0 / 0.6);
}
除了带有一定透明度的纯黑色叠加层之外,还可以是带有一定透明度的其他颜色的叠加层:
调整颜色和透明度,可以得到不同带有透明度的纯色叠加层:
纯色和渐变混合的叠加层
这种方案是前面渐变和带有一定透明度纯色的混合物。
.card__content {
background-color: rgba(0, 0, 0, 0.4);
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 0.8),
rgba(0, 0, 0, 0) 60%,
rgba(0, 0, 0, 0.8) 100%
);
}
半透明的图片
这个效果由三个层组成:
- 纯色的底部
- 带有一定透明度的图片
- 文本层
如果用 CSS 来构建这个效果,我们可以这样来构建:
.card::before {
content:'';
background-color: #000;
}
.card__thumb {
opacity: .5
}
图片的高斯模糊
我们可以像 《使用CSS构建Glassmorphism UI效果》一文中介绍的一样,给图片添加高斯模糊的效果:
.card__content {
background-color: rgba(255, 255, 255, 0.06);
backdrop-filter: blur(5px);
}
这种效果,还可以使用 @Adam Argyle 在 Twitter 分享的方案:
可以使用 CSS 的自定义属性,让事情变得更简单:
图片置灰
图片置灰和上面的高斯模糊有点类似,可以直接在图片运用滤镜的效果:
.card__thumb {
filter: grayscale(1);
}
给叠加文本添加阴影
我们除了设置图片的或叠加层效果之外,还可以给叠加的文本添加效果,比如给文本运用 text-shadow
效果:
.card__content {
text-shadow: 0 2px 3px rgba(0, 0, 0, 0.3);
}
文本高亮
文本高亮就是在叠加文本上添加一个高亮的纯色,比如像下面这个示例中的 Tags,添加一个纯色的高亮色:
.card__tag {
align-self: start;
justify-self: start;
z-index: 3;
margin-top: 2rem;
border-radius: 0 10rem 10rem 0;
grid-area: 1 / -1;
}
我们把所有效果集中到一起:
选择一个具有可访问性的叠加颜色
文本叠加在图片时添加一个叠加层(渐变、纯色或图片高斯模糊等)主要是为了解决可读性问题(也就是 A11Y)。即使是这样,也并不代表你添加的叠加层就能让文本易于阅读。庆幸的是,我们可以使用浏览器一些工具,比如 Firefox,可以对渐变进行色彩对比测试。它会给你测量的最小和最大的对比度:
除了使用上面这样的测试工具之外,还可以使用 @Yaphi 写的工具,可以计算出理想的不透明度,以便使对比度符合 WCAG 标准:
可以调整叠加层颜色和文本颜色:
文本叠加动效
让叠加在图片上的文本变得易读,我们可以在他们之间添加一个渐变叠加层。除此之外,我们还可以在其基础上添加一定的动效,比如 @Mahesh ambure 在 Codepen 上构建的两个 Demo(Part1 和 Part2):