16

深入理解CSS background-blend-mode的作用机制

 4 years ago
source link: https://www.zhangxinxu.com/wordpress/2020/07/css-background-blend-mode/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

byzhangxinxu from https://www.zhangxinxu.com/wordpress/?p=5474

本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

一、可能都知道的

首先,讲两点大家可能都知道的知识点:

  1. background-blend-mode 本身就带有隔离特性,也就是一个元素应用 background-blend-mode 背景混合模式,最终的效果只会受当前元素的背景图像和背景颜色影响,不会受视觉上处于当前区域其他任意元素影响。
  2. 应用 background-blend-mode 属性后,不仅各个图像之间要进行混合,同时还要和背景色进行混合。

接下来,讲下大家可能并不知道的知识点,这也是很多人搞不清楚为什么 background-blend-mode 属性这么渲染的原因。

二、可能不知道的

1. 背景顺序影响混合效果

混合效果和 background 属性中背景图像的顺序密切相关。在CSS多背景中,越是语法中靠后的背景图像的层级越是低,这也是为何 background-color 要写在最后语法才合法的原因,因为背景色的层级永远是最低的。

例如下面2个元素:

<div class="ball"></div>
<div class="ball2"></div>

设置背景混合模式为叠加,但是两个元素的背景图像的顺序是相反的,代码如下所示:

.ball {
    width: 200px; height: 200px;
    border-radius: 50%;
    background: linear-gradient(deeppink, deeppink), linear-gradient(deepskyblue, deepskyblue);
    /* 应用叠加混合模式 */
    background-blend-mode: overlay;
}
.ball2 {
    width: 200px; height: 200px;
    border-radius: 50%;
    background: linear-gradient(deepskyblue, deepskyblue), linear-gradient(deeppink, deeppink);
    /* 应用叠加混合模式 */
    background-blend-mode: overlay;
}

结果下图所示, .ball 元素表现为 deeppink 叠加后面的 deepskyblue ,最终混合颜色偏蓝; .ball2 元素表现为 deepskyblue 叠加后面的 deeppink ,最终混合颜色偏紫。

MNzaUj3.png!web

2. 混合效果是多个混合属性同时作用的结果

很多开发人员并不清楚, background-blend-mode 支持其实是可以设置多个混合模式值,分别对应不同的背景图像,这一点和仅仅支持一个混合模式值的 mix-blend-mode 属性是不一样的。例如:

.ball {
    background: linear-gradient(deeppink, deeppink), 
        linear-gradient(deepskyblue, deepskyblue);
    background-blend-mode: overlay;
}

实际上等同于:

.ball {
    background: linear-gradient(deeppink, deeppink), 
        linear-gradient(deepskyblue, deepskyblue);
    background-blend-mode: overlay overlay;
}

也就是, deeppink 实际上叠加的是deepskyblue和背景色(此例是透明), deepskyblue 叠加的是背景色(此例是透明)。

换言之,实际上,每个背景图像都有一个自己的混合模式值,这是和 mix-blend-mode 属性有着巨大区别的!通常,在使用 mix-blend-mode 属性的场景中,我们只会把混合模式设置在顶层元素上,而不会每一层元素都设置,于是带来了一个由此及彼的严重的思维误区,以为背景混合模式设置的值也是作用在对顶层的背景图像上的,从而导致很多开发者想不通 background-blend-mode 属性的渲染表现和自己预期的不一样。

我们通过一个案例演示下 background-blend-mode 属性的多个值是如何和背景图像一一对应的。

<div class="box"></div>
.box {
    width: 200px; height: 200px;
    background: linear-gradient(to right bottom, deeppink 50%, transparent 50%),
        linear-gradient(to top right, deeppink 50%, transparent 50%), 
        darkblue;
    background-blend-mode: multiply, screen;
    position: relative;
}
/* 中间原始的deeppink色值 */
.box::before {
    content: '';
    position: absolute;
    width: 33%; height: 33%;
    inset: 0;
    margin: auto;
    background-color: deeppink;
}

此时 .box 元素总共呈现出了5种颜色,每种颜色的RGB色值和如何产生的如下图所示。

e6fmUv6.png!web

其中:

  • 中间标注了序号①的正方形区域没有应用任何混合模式,颜色就是 deeppink ,作用是方便大家和区域③、区域⑤处的颜色进行对比。
  • 区域②就是背景色 darkblue ,因为两个斜向渐变均没有覆盖到这个区域,直接暴露了设置的背景色。
  • 区域③和区域⑤是下层渐变,也就是 background 属性值中位置靠后的渐变,对应的混合模式也是 background-blend-mode 属性值靠后的那个,也就是 screen ,滤色模式,可以让颜色变亮。
  • 区域④和区域⑤是上层渐变,也就是 background 属性值中位置靠前的渐变,对应的混合模式也是 background-blend-mode 属性值靠前的那个,也就是 multiply ,正片叠底模式,可以让颜色变暗。
  • 区域③的颜色表现源自渐变色 deeppink 和背景色 darkblue 进行滤色混合的效果,可以看出最终呈现的颜色比 deeppink 更亮了,最终混合后的色值是 rgb(255,20,206)
  • 区域④的颜色表现源自渐变色 deeppink 和背景色 darkblue 进行正片叠底混合的效果,可以看出最终呈现的颜色比 darkblue 更深了,最终混合后的色值是 rgb(0,0,80)
  • 区域⑤最复杂,理解了这个,也就理解了大多数的 background-blend-mode 属性的渲染表现了。

    区域⑤总共有3层,分别是:上层的 deeppink ,混合模式是 multiply ;下层的 deeppink ,混合模式是 screen ;底层的背景色 darkblue

    于是,最终的色值表现是上层的 deeppink 使用 multiply 混合下层的 deeppink 和背景色 darkblue 使用 screen 混合后的色值。

    由于下层的 deeppink 和背景色 darkblue 使用 screen 混合后的色值就是区域③的颜色。因此,区域⑤的颜色就是 deeppink 和区域③的色值 rgb(255,20,206) 进行正片叠底混合后的色值,结果是 rgb(255,1,119)

以上就是 .box 元素5个颜色各自呈现的原理所在。

三、background-blend-mode与渐变图标的实现

最后再看看看,为何大多数人没办法使用 background-blend-mode 实现渐变图标的效果。

例如,现在有1个颜色很深的删除小图标,理论上,我们可以使用 lighten 混合模式实现渐变效果,因为 lighten 的效果是哪个颜色浅使用哪个颜色,由于图标本身颜色很深,因此,一定会显示渐变色,只要给图标加一个白色底就可以,于是,按照这个思路,很多人就写了如下所示的CSS代码:

.icon-delete {
    background: linear-gradient(deepskyblue, deeppink), 
        url(delete.png), white;
    background-blend-mode: lighten;
}

乍一看,似乎逻辑上无懈可击,渐变和白底黑色的图标进行变亮混合,怎么想黑色图标也应该变成渐变色啊,很遗憾,最终的渐变并不是渐变色,而是纯白色,为什么会有这样的结果呢?

那是因为这里的 background-blend-mode:lighten 实际上是一个缩写,或者简写,实际上真实的计算值是 lighten lighten ,代码如下所示:

.icon-delete {
    background: linear-gradient(deepskyblue, deeppink), 
        url(delete.png), white;
    /* 实际上的计算值 */
    background-blend-mode: lighten lighten;
}

也就是删除图标 delete.png 也应用了混合模式 lighten ,和白色背景色进行了混合,于是变成了纯白色。

知道了问题所在,也就知道了该如何解决了,很简单,让 delete.png 和白色背景色混合后还保持原始图标的模样即可,下面两种CSS方法均可以:

.icon-delete {
    background: linear-gradient(deepskyblue, deeppink), 
        url(delete.png), white;
    /* PNG图标的混合模式单独设成darken */
    background-blend-mode: lighten darken;
}

或者是:

.icon-delete {
    background: linear-gradient(deepskyblue, deeppink), 
        url(delete.png), white;
    /* PNG图标的混合模式单独设成normal */
    background-blend-mode: lighten normal;
}

推荐使用 normal 关键字,因为更巧妙,性能也更好一点。最终实现的效果如下图所示。

BB732qI.png!web

当然,渐变图标效果最好的实现方法肯定是 CSS mask 遮罩属性 ,这里的使用混合模式实现的渐变图标会有白色的底,并不是完美的实现方法,主要目的还是让大家了解 background-blend-mode 属性的渲染细节。

四、background-blend-mode的补全规则

background-blend-mode 的属性值的数量和 background-image 不匹配的时候,遵循下面的应用规则:

  • 如果 background-blend-mode 的值的数量大于 background-image ,则多出来的混合模式会被忽略,例如:

    .example { 
        background: linear-gradient(deepskyblue, deeppink), white;
        background-blend-mode: lighten, darken;
    }

    等同于:

    .example { 
        background: linear-gradient(deepskyblue, deeppink), white;
        background-blend-mode: lighten;
    }
  • 如果 background-blend-mode 的值的数量少于 background-image ,则会重复完整的 background-blend-mode 属性值进行补全,例如:

    .example { 
        background: linear-gradient(deepskyblue, deeppink), 
            linear-gradient(deepskyblue, deeppink),
            linear-gradient(deepskyblue, deeppink), white;
        background-blend-mode: lighten, darken;
    }

    等同于:

    .example { 
        background: linear-gradient(deepskyblue, deeppink), 
            linear-gradient(deepskyblue, deeppink),
            linear-gradient(deepskyblue, deeppink), white;
        background-blend-mode: lighten, darken, lighten;
    }

    也就是 lighten, darken 一起进行重复,而不是仅仅重复最后一个混合模式值。因此,补全的值的 lighten

五、结语

CSS background-blend-mode 属性可以让各个背景图像之间应用混合模式。

background-blend-mode 属性的使用频率要明显低于 mix-blend-mode 属性。

原因在于:

  1. 真实世界的照片图像很少作为 background-image 背景图像呈现,因为不利于无障碍访问,而混合模式设计的初衷就是这类照片图像的处理;
  2. background-blend-mode 属性作用机制不像 mix-blend-mode 属性那么单纯,很多开发人员并不能很好地驾驭。例如请使用混合模式让透明背景的小图标变成渐变图标,使用 mix-blend-mode 属性实现的人有很多,但是能够使用 background-blend-mode 属性实现的人寥寥无几。

因此,目前 background-blend-mode 属性更常见的应用是用来丰富CSS的背景纹理,例如:

zmmqIjy.png!web

具体就不展开,非本文主要内容。

以上就是本文的全部内容,感谢阅读,如果你觉得内容还不错,欢迎分享。

emURJjj.png!web

本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。

本文地址: https://www.zhangxinxu.com/wordpress/?p=9499

(本篇完)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK