首页与我联系

「基础」CSS Blend Modes 混合模式的学习与整理(上)

By 前端达人
Published in 2-CSS3
August 23, 2022
1 min read
「基础」CSS Blend Modes 混合模式的学习与整理(上)

混合模式,这个CSS3的新特性,这个特性的问世已经有好几年了,但是我一直很少尝试使用,之所以很少使用,主要是因为缺乏业务场景使用,还有一个重要的原因就是我虽然知道有这个特性,但是对其背后的原理和逻辑一直很模糊,尤其对于一个 Photoshop 都不太熟悉的人,更难上手这些东西的使用了。以下是 Photoshop 图层混合模式的概览,让我们先大概对混合模式有个大概的印象。

1000.webp

当我去想了解清楚到底什么是混合模式?网上找了一堆文章,虽然也罗列了一些示例和说明,但是背后的逻辑也是让我稀里糊涂的。今天看到一些文章和示例,觉得很酷,我觉得有必要了解清楚,因此通过归纳的形式让自己梳理清楚,彻底弄明白。

混合模式(Blend Modes

在CSS中,由于定位,两个元素可能出现部分重叠,前面的部分会遮住后面的部分,如果有 alpha 通道,而且小于1,我们就能看到后面的元素。熟悉 Photoshop 的朋友,重叠的图层有多重混合模式,现在 CSS 提供了这样的混合策略。目前提供了两种策略:混合元素(mix-blend-mode) 和 背景混合(background-blend-mode)。

  • mix-blend-mode:将前景层与它们重叠的层混合。
  • background-blend-mode:混合背景图像和颜色,尤其一个元素有多个背景图,而且背景图有重叠,此时用背景混合模式。

混合的逻辑是什么?

在介绍这前,我们先了解混合的逻辑是什么?

混合意味着组合两层(堆叠在另一层之上)并得到一个单层。这两个层可以是两个兄弟元素,在这种情况下,我们使用的 CSS 属性是 mix-blend-mode。它们也可以是两个背景层,在这种情况下,我们使用的 CSS 属性是 background-blend-mode。请注意,当我谈论混合“兄弟”时,这包括将元素与伪元素或文本内容或其父元素的背景混合。当涉及到背景层时,我所说的不仅仅是背景图像层——背景颜色也是一个层。

混合两个图层时,上面的图层称为源图层,而下面的图层称为目标图层。这些名字没有多大意义,只是我们在介绍逻辑的时候比较方便。至少对我们来说,这个层是输入,我们关注结果如何输出而已。

为了解释方便,我们暂且称源图层称作顶层,模板图层称作底层。

blend_terminology.webp

我们如何精确地组合两层取决于所使用的特定混合模式,但它总是按像素计算。例如,下图使用multiply blend mode 来组合两个图层,表示为像素网格。

blend_pixels.webp

如果多于两个图层,该如何混合呢?其逻辑将从最后一个图层开始,两两混合,得到的混合结果,再与上一个图层再次合成,直到最上面一个图层为止。可能你还不太理解,看完下图,你就会明白了。

blend_multi.webp

我们可以使用不同的混合模式,比如最底下的两个图层使用 difference 模式得到的结果,再与第三个图层采用 multiply 模式混合。

关于图层通道,合成的红色通道仅取决于源红色通道和目标的红色通道;生成的绿色通道仅取决于源的绿色通道和目标的绿色通道,蓝色通道也是如此,我们可以用如下公式进行表示:

R = fB(Rs, Rd)
G = fB(Gs, Gd)
B = fB(Bs, Bd)

需要记住的是,RGB 值可以在 [0, 255] 区间中表示,也可以用百分比进行表示[0%, 100%] ,比如rgb(220, 20, 60) 可以用 rgb(86.3%, 7.8%, 23.5%) 表示,这两个是等效的。黑色  rgb(0, 0, 0)可以用 rgb(0%, 0%, 0%),白色rgb(255, 255, 255)可以用 rgb(100%, 100%, 100%)

混合元素(mix-blend-mode)

前面已经说过,混合元素的模式将顶层与底层合并。层可以是父元素、根元素或堆栈中目标元素下方的元素的背景颜色或图像。我们来看下段代码,HTML部分如下段代码所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>mix-blend-mode</title>
    <link rel="stylesheet" href="mix-blend-mode.css">
</head>
<body>
    <div>
        <p>This is a paragraph that's positioned below the image in the stack. </p>
        <img src="dahlia.jpg">
    </div>
</body>
</html>

mix-blend-mode.css 部分的代码如下所示:

div {
    background-image: linear-gradient(to left, #f30, #fc0);
    width: 60vw;
    margin: 3rem auto;
    position: relative;
}
p {
    position: absolute;
    color: black;
    margin: 4rem;
    font-size: 6.4rem;
}
img {
    display: block;
    height: auto;
    width: 100%;
}

最终完成后的效果如下所示:

VisualEffectsPreBlendMode.png

请注意,上图中的文字很难阅读。那是因为文本和图像之间的对比度不足。在实际项目中,您应该为 p 元素添加背景颜色或渐变以使其清晰易读。还要确保前景色和背景色之间有足够的对比度。

完成上述代码后,我们开始设置混合模式的属性。

1、差值属性(difference)

由于 p 元素是绝对定位的,因此文本会覆盖照片。还要注意,照片填充了其父容器的整个宽度和高度,因此我们看不到它的背景渐变。现在让我们将 mix-blend-mode 添加 img 混合模式的属性。这里我们使用 difference 差值模式看下效果。

该混合模式会查看每个通道中的颜色信息,比较底层和上层,用较亮的像素点的像素值减去较暗的像素点的像素值。 与白色混合将使底色反相(补色);与黑色混合则不产生颜色变化。用数学公式表达就是两个值相减后的绝对值。

Ch = fB(Chs, Chd) = |Chs - Chd|

如下图所示,顶层图层分别为黑、白、 渐变色图层。 底层为与顶层同样的渐变图层,如下图所示:

top.png

合成后的效果

bottom.png

合成后效果,与黑色合成为底层原本的颜色,与白色合成则为对应颜色的补色(或反向),同样的颜色差异则为黑色。

解释到这里,我们接着上面的代码,设置图片的混合属性为 difference,示例代码如下:

img {
    display: block;
    height: auto;
    width: 100%;

    mix-blend-mode: difference;
}

现在照片已移至图层堆栈的顶部(如下图所示),与段落文本及其父 div 的背景图像混合。

VisualEffectsPostBlendMode.png

2、排除(exclusion)

排除模式,相对差值模式,相对更加温和,因为其数学公式如下所示,两个相加,

Ch = fB(Chs, Chd) = Chs + Chd - 2·Chs·Chd

如果顶层为黑色,合成后的颜色,为底层的颜色,从数学公式中可以看出:

Ch = fB(0, Chd) = 0 + Chd - 2·0·Chd = Chd - 0 = Chd

如果底层为黑色,合成后的颜色,为顶层的颜色:

Ch = fB(Chs, 0) = Chs + 0 - 2·Chs·0 = Chs - 0 = Chs

如果顶层或底层为白色的话,合成的颜色,则为对应颜色的补色:

Ch = fB(1, Chd) = 1 + Chd - 2·1·Chd = 1 + Chd - 2·Chd = 1 - Chd
Ch = fB(Chs, 1) = Chs + 1 - 2·Chs·1 = Chs + 1 - 2·Chs = 1 - Chs

为了更好的理解,我们还是用下图来解释下,如果顶层分别为黑色、白色,如下图所示:

exclusion1.png

使用排除的方式,合成的效果如下图所示:

exclusion2.png

3、示例

介绍完了差值和排除属性模式,我们看个示例,看看在实际中如何应用。

文字状态变化效果

首先我们在HTML文件里,定义一段文本,如下所示

<p>Hello, <a href='#'>World</a>!</div>

接下来,我们首先设置一些基本样式,将文本放在屏幕中间,增大字体大小,在正文上设置背景,在段落和链接上设置颜色。

body {
  display: grid;
  place-content: center;
  height: 100vh;
  background: #222;
  color: #ddd;
  font-size: clamp(1.25em, 15vw, 7em);
}

a { color: gold; }

完成后的效果如下图所示:

blend_0_ex_1a_step_00.webp

接下来,我们使用 ::after 伪元素在黄色链接上,定义个与文本颜色相同的背景颜色进行覆盖,示例代码如下:

a {
  position: relative;
  color: gold;
  
  &::after {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;
    background: currentColor;
    content: '';
  }
}

链接被蒙上黄色背景后的效果:

blend_0_ex_1a_step_01.webp

接下来,你应该拆到我该做什么了,不至于一个黄色的背景覆盖在链接文字上,我们应该使用混合模式的特性,使用差值(difference),底层和顶层颜色一致时,混合后,重合的部分则显示黑色。修改后的代码如下:

p { isolation: isolate; }

a {
  /* same as before */
  
  &::after {
    /* same as before */
    mix-blend-mode: difference;
  }
}

如你所料,完成后的效果如下图所示:

blend_0_ex_1a_step_02.webp

接下来我们做一些动画效果,使用伪元素 hover 经过效果,让链接上的背景色由隐藏到显示,这里我们使用 scale(0) 让背景隐藏。

a {
  /* same as before */
  text-decoration: none;
  
  &::after {
    /* same as before */
    transform: scale(0);
  }

  &:focus { outline: none }
  &:focus, &:hover { &::after { transform: none; } }
}

上述代码我们删除了链接的下划线和选中后的边框,鼠标经过后的效果,如下图所示:

blend_0_ex_1a_step_03.webp

上述的动画效果还不够平滑,我们需要添加 transition 属性,让其更加平滑:

a {
  /* same as before */
  
  &::after {
    /* same as before */
    transition: transform .25s;
  }
}

如下图所示,效果是不是更好呢: blend_0_ex_1a_step_04.webp

由于背景的默认中心点在中央,所以效果是从中间向两边发散,接下来我们来更改效果,让你背景色由底部出现的效果,更改背景的中心点在底部,如下段代码所示:

a {
  /* same as before */
  
  &::after {
    /* same as before */
    transform-origin: 0 100%;
    transform: scaleY(.05);
  }
}

更改后的效果如下图所示,效果更加自然,由底部往上推的效果

blend_0_ex_1a_step_05.webp

结束语

由于篇幅原因,今天的文章就介绍到这里,接下来的文章,我们继续学习背景混合模式,敬请期待…

前端达人公众号.jpg

注:本文属于原创文章,版权属于「前端达人」公众号及 qianduandaren.com 所有,未经授权,谢绝一切形式的转载


Tags

css3basic
Previous Article
使用 React 和 Next.js 做一个简单的博客网站(下)
前端达人

前端达人

专注前端知识分享

Table Of Contents

1
混合模式(Blend Modes)
2
混合的逻辑是什么?
3
混合元素(mix-blend-mode)
4
结束语

相关文章

「基础」CSS Blend Modes 混合模式的学习与整理(下)
August 24, 2022
1 min

前端站点

VUE官网React官网TypeScript官网

公众号:前端达人

前端达人公众号