还记得 2017 年,我们响应朋友的邀约从高德离职出来创业的时候,遇到了一个相对来说有点特殊的需求,动态的文字有长有短,但是需要智能适配背景的颜色变成其对比色。大概效果如下:

 

仔细看会发现,哪怕半个文字存在于两个不同的背景色之间,这个文字也会被分割成两个颜色。

看到这样的需求,大多数人第一时间想到的是,文字元素有两个,是完全重叠的两层,一层是黑色,一层是白色,然后通过遮罩实现。没错,这样的确可以实现这样的效果,但是也会让 DOM 结构过于复杂。

于是,今天我就带领大家只用一个文字元素,使用混合模式实现这样的效果。那么我们就开始吧!


一、构建背景容器

我们就用一个 div 元素实现黑色边框,一半黑色一半白色,分割线还是倾斜背景容器。 

<div><div>

DOM 结构尽可能的简约,所以就直接这样放一个 div 即可。核心是需要使用 CSS 控制其显示样式

先不想那么多,我们先给容器一个大小黑色边框,并设置背景颜色白色

div {
  height: 500px;
  border: 5px solid #000;
  background: #fff;
}

 很明显,现在只有一个框。

 

这个时候,我们需要让背景一半黑色,并且黑色部分构成一个直角梯形。自然会想到使用该元素的 before 或者 after 两个伪元素来实现。

既然要使用伪元素,大概率涉及到了伪元素定位,那么我们先给 div 元素一个相对定位

div {
  position: relative;
  height: 500px;
  border: 5px solid #000;
  background: #fff;
}

小小知识点:

  • position 属性是控制元素定位的,默认值为 static

  • 若一个元素的 position 属性值为绝对定位(absolute),即可通过 topbottom 两个属性控制该元素竖直偏移,也可以通过 rightleft 两个属性控制该元素水平偏移

  • 没有设置 topbottom 两个属性,则竖直方向偏移和 position 的值为 static 显示的一样;若没有设置 rightleft 两个属性,则水平方向偏移和 position 的值为 static 显示的一样。

  • 无论水平方向还是竖直方向,只要设置了偏移属性,那么就需要看该元素父元素的 position 是什么值。若父元素的 position 不是 static,那么就会以该父元素容器范围基准开始偏移;若父元素的 position 是 static,那么就会无视该父元素管理范围,继续向上寻找“爷爷”元素,直到找到 position 不是 static 的元素,或者直接以 body 元素为基准

我曾经在《【欧洲杯】用纯前端写一个滚动的足球(上)》这篇文章中讲解过如何使用伪元素正五边形。现在我们需要使用 before 和 after 两个伪元素组成一个直角梯形,最简单的方式就是使用 before 写成一个矩形,然后使用 after 写成一个直角三角形,然后拼接在一起。

 

按照这样的思路,我们直接用 CSS 把这个直角梯形写出来:

div::before,
div::after {
  position: absolute;
  top: 0;
  bottom: 0;
  display: block;
  content: "";
}
div::before {
  left: 0;
  width: 40%;
  background: #000;
}
div::after {
  left: 40%;
  width: 0;
  height: 0;
  border-top: 250px solid transparent;
  border-right: 100px solid transparent;
  border-bottom: 250px solid #000;
  border-left: 100px solid #000;
}

按照这样的结构设计:

 

我们得到如下结果:

 

这就是我们想要的背景容器。


二、放入文字

一般来说,直接在 div 中写入文字即可。考虑到对鼠标悬停存在动画效果,我们就在 div 中放一个 h1 标签。

<div>
  <h1>实现文字智能适配背景</h1>
</div>

通过 CSS 控制文字的位置大小

h1 {
  position: absolute;
  left: 40%;
  z-index: 1;
  font-size: 9rem;
}

设置了 z-index 属性,让其显示在 div 元素的伪元素上方

默认情况下,文字的颜色是黑色的:

 

设置文字颜色为白色:

h1 {
  position: absolute;
  left: 40%;
  z-index: 1;
  font-size: 9rem;
  color: #fff;
}

显示效果如下:

 

为了看的更加清楚,我们给文字增加一个动画,让鼠标进入的时候,文字向左滑动,反之回到原位。 

h1 {
  position: absolute;
  left: 40%;
  z-index: 1;
  font-size: 9rem;
  color: #fff;
  transition: 0.5s;
}
div:hover > h1 {
  transform: translateX(-60%);
}

可以看到这样的效果:

 

这样,我们已经把文字插入到元素中了。但是,文字在白色部分是看不出来的,怎么办呢?掌声有请我们今天的主角的——混合模式! 


三、混合模式

需要让文字智能适配背景的颜色,在黑色部分显示白色,在白色部分显示黑色,我们需要用到混合模式

想要把混合模式完全搞懂,需要对颜色及其三要素有一定的了解。这里完全可以单独开一门课程进行讲解,今天涉及到了,就只能给大家做一个简单的介绍。

  • 色调,是色彩首要特征,是区别各种不同色彩的最准确标准,即各类色彩的相貌称谓
  • 饱和度,又叫纯度,是指色彩的鲜艳程度

  • 明度,也叫亮度,是眼睛对光源和物体表面的明暗程度的感觉,主要是由光线强弱决定的一种视觉经验

相信大多数人第一次接触混合模式,是在 Photoshop 中。

 

在 CSS 中,混合模式是用于控制 HTML 元素间颜色混合模式。它允许某个 HTML 元素的内容与其背后的背景或其他 HTML 元素内容以特定的方式相互作用,从而实现相对复杂叠加效果,从而提升页面的视觉层次艺术感

在 CSS 中,主要是 background-blend-mode 属性和 mix-blend-mode 两个属性来实现元素的混合模式

  • background-blend-mode - 指定 HTML 元素的背景层(包括背景颜色背景图片等)之间的混合模式

  • mix-blend-mode - 指定一个 HTML 元素的内容(包括文字内嵌图像等)与其下方 HTML 元素的混合模式

标准混合模式有如下 16 个:

  • Normal(默认):

  • 不进行特殊混合,上层的 HTML 元素直接盖住下层的 HTML 元素;

  • 这是默认混合模式,相当于没有混合

  • Multiply(正片叠底):

  • 上层 HTML 元素中的颜色下层 HTML 元素颜色每一个分量进行相乘,一般情况下,计算后的结果颜色比原本的颜色更暗

  • 对于上层 HTML 元素中的颜色纯黑色纯白色的,混合后的结果将分别保持下层 HTML 元素颜色不变或变为纯黑色

  • Screen(滤色):

  • 类似于两层幻灯片重叠的效果,上层 HTML 元素颜色下层 HTML 元素颜色互补色相乘,然后取反

  • 一般情况下,计算后的结果颜色比原本的颜色更亮

  • 对于上层 HTML 元素中的颜色纯黑色纯白色的,混合后会使下层 HTML 元素颜色不变或变为纯白色

  • Overlay(叠加):

  • 结合了 Multiply 和 Screen 模式的特点;

  • 对于下层 HTML 元素颜色较暗的区域,使用 Multiply 模式;

  • 对于下层 HTML 元素颜色较亮的区域,使用 Screen 模式;

  • 这种模式可以增强对比度

  • Darken(变暗):

  • 对于每个像素位置,取上层 HTML 元素颜色下层 HTML 元素颜色较暗那个颜色作为结果颜色

  • 该模式倾向于保留两个层叠的 HTML 元素最深色彩

  • Lighten(变亮):

  • 类似于 Darken,只不过取的是两层 HTML 元素颜色较亮的那个颜色作为结果颜色

  • 该模式倾向于保留两个层叠的 HTML 元素最浅色彩

  • Color-Dodge(颜色减淡):

  • 上层 HTML 元素颜色根据下层 HTML 元素颜色信息中的亮度调整自身亮度,使得结果颜色变亮

  • 下层 HTML 元素颜色较暗时,影响较小

  • 下层 HTML 元素颜色接近白色时,上层 HTML 元素颜色明显变亮甚至完全变为白色

  • Color-Burn(颜色加深):

  • 与 Color-Dodge 反过来,上层 HTML 元素颜色根据下层 HTML 元素颜色信息中的亮度调整自身亮度,使得结果颜色变暗

  • 下层 HTML 元素颜色较亮时,影响较小

  • 下层 HTML 元素颜色接近黑色时,上层 HTML 元素颜色明显变暗甚至完全变为黑色

  • Hard-Light(强光):

  • 类似于 Overlay,但作用于下层 HTML 元素颜色

  • 上层 HTML 元素颜色类似于一个光源,对下层 HTML 元素颜色施加明暗影响

  • 上层 HTML 元素颜色纯黑色纯白色,则会使下层 HTML 元素颜色变暗变亮

  • Soft-Light(柔光):

  • 与 Hard-Light 相似,但效果更为柔和

  • 上层 HTML 元素颜色下层 HTML 元素颜色明暗影响较小,产生类似半透明材料覆盖的效果。

  • Difference(差值):

  • 计算上层 HTML 元素颜色下层 HTML 元素颜色之间的色差,结果为两者之间对比色

  • 当两层颜色相同时,结果为黑色

  • 当两层颜色互补时,结果为白色

  • Exclusion(排除):

  • 与 Difference 类似,但产生的对比度较低

  • 结果颜色比 Difference 模式更柔和,且不会出现纯黑色纯白色

  • Hue(色相):

  • 上层 HTML 元素颜色信息中的色相下层 HTML 元素颜色信息中的饱和度亮度,生成新的颜色

  • 下层 HTML 元素颜色信息中的色调上层 HTML 元素颜色信息中的色调替换,但饱和度亮度保持不变

  • Saturation(饱和度):

  • 下层 HTML 元素颜色信息中的色相亮度,以及上层 HTML 元素颜色信息中的饱和度,生成新的颜色

  • 下层 HTML 元素颜色信息中的饱和度上层 HTML 元素颜色信息中的饱和度替换其他属性保持不变

  • Color(颜色):

  • 上层 HTML 元素颜色信息中的色相饱和度,以及下层 HTML 元素颜色信息中的亮度,生成新的颜色

  • 下层 HTML 元素颜色信息中的色调饱和度上层 HTML 元素颜色信息中的色调饱和度替换亮度保持不变

  • Luminosity(亮度/明度):

  • 上层 HTML 元素颜色信息中的亮度,与下层 HTML 元素颜色信息中的色相饱和度结合,生成新的颜色

  • 下层 HTML 元素颜色信息中的亮度上层 HTML 元素颜色信息中的亮度替换色调饱和度保持不变

除了标准混合模式,还有分离混合模式和 CSS Paint API 混合模式,这里也做一个简单的介绍:

  • 分离混合模式 - 在 normal、multiply、screen、darken、lighten、color-dodge、color-burn、hard-light、soft-light、difference、exclusion 这 11 种标准混合模式中还可以加上前缀 difference,形成如 difference-normal 等分离混合模式,用于独立控制 RGB 通道和 alpha 通道混合

分离混合模式由于其计算简单性效率,在某些情况下可能更适合性能敏感的应用场景。

  • CSS Paint API混合模式 - 一种允许开发者使用 JavaScript 编写自定义绘制逻辑来生成 CSS 背景、边框、内容图像现代 Web 技术

CSS Paint API 混合模式需要在支持 CSS Paint API 的浏览器中才能使用,是一种特殊混合模式,如 plus-darkerplus-lighter 等;

配合 mix-blend-mode 属性,CSS Paint API 可以实现更加动态灵活复杂颜色混合效果

混合模式及其色彩方面的知识还有很多,这里就不做过多的展开了。

咱们根据目前的知识,结合咱们的案例,感觉最适合的是 Difference‍ 模式。于是我们在控制文字的 CSS 中添加这个混合模式

h1 {
  position: absolute;
  left: 40%;
  z-index: 1;
  font-size: 9rem;
  color: #fff;
  transition: 0.5s;
  mix-blend-mode: difference;
}

这样,我们就得到了需要的效果:

 


完整源码

最后,我们还是把完整的源代码贡献给大家吧!

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
  margin: 0;
  padding: 0;
  border: none;
  font-size: 62.5%;
}
div {
  position: relative;
  height: 500px;
  border: 5px solid #000;
  background: #fff;
  line-height: 500px;
  cursor: pointer;
}
div::before,
div::after {
  position: absolute;
  top: 0;
  bottom: 0;
  display: block;
  content: "";
}
div::before {
  left: 0;
  width: 40%;
  background: #000;
}
div::after {
  left: 40%;
  width: 0;
  height: 0;
  border-top: 250px solid transparent;
  border-right: 100px solid transparent;
  border-bottom: 250px solid #000;
  border-left: 100px solid #000;
}
h1 {
  position: absolute;
  left: 40%;
  z-index: 1;
  font-size: 9rem;
  color: #fff;
  transition: 0.5s;
  mix-blend-mode: difference;
}
div:hover > h1 {
  transform: translateX(-60%);
}
</style>
</head>
<body>
<div>
  <h1>实现文字智能适配背景</h1>
</div>
</body>
</html>

若大家对混合模式或者色彩方面的知识感兴趣的,欢迎大家留言,我会在将来做成视频或者更加详细的文章进行讲解。让我们拭目以待吧!

关注我,为您送上更多精彩内容! 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐