CSS mix-blend-mode 父子元素色彩叠加混合会碰撞出什么样的火花

简介: CSS mix-blend-mode 父子元素色彩叠加混合会碰撞出什么样的火花

mix-blend-mode是一个非常有趣的CSS属性,它可以让你的元素与它的父元素进行混合,混合的子元素可以是任何元素,包括文本、图片、SVG等,接下来就和我一起来看看它的效果吧。


先看效果:

简介


什么是混合模式


在开始之前我们先来了解一下什么是混合模式,混合模式(Blend Mode)是图像处理中的一种技术,它可以让你的图像与背景图像进行混合,从而得到一个新的图像。


混合模式常见于图像处理软件中,比如PS(Photoshop)AI(Illustrator)AE(After Effects)等。


常见的混合模式有:


  • 正片叠底
  • 叠加
  • 柔光
  • 颜色加深
  • 颜色减淡
  • 差值
  • 反差
  • 变暗
  • 变亮
  • 滤色


这些东西通常是需要图像处理软件来完成的,但是今天我们就可以在CSS中实现这些效果了。


什么是mix-blend-mode


mix-blend-modeCSS3中新增的一个属性,它可以让你的元素与它的父元素进行混合,从而得到一个新的图像。


mix-blend-mode的值有:


  • normal:默认值,没有混合效果
  • multiply:正片叠底
  • screen:滤色
  • overlay:叠加
  • darken:变暗
  • lighten:变亮
  • color-dodge:颜色减淡
  • color-burn:颜色加深
  • hard-light:强光
  • soft-light:柔光
  • difference:差值
  • exclusion:排除
  • hue:色相
  • saturation:饱和度
  • color:颜色
  • luminosity:亮度


可以看到这些值就是我们常见的混合模式,这就说明我们可以在CSS中实现这些效果了,接下来我们就来看看每种混合模式有什么区别。


混合模式的效果


正片叠底


正片叠底的作用是让两个图层的颜色相乘,从而得到一个新的图像,叠底就是让底层的颜色影响上层的颜色。


正片叠底是一种非常常见的混合模式,它的效果就是将两个图像的像素点的色值相乘,然后再除以255,得到的结果就是新的像素点的色值,这样就可以得到一个新的图像。


例如两个图像的像素点的色值分别为:


  • 图像1:#ff0000
  • 图像2:#00ff00
  • 结果:#000000


这样就可以得到一个新的图像,它的像素点的色值为#000000


在CSS中我们可以通过mix-blend-mode: multiply来实现这种效果。

<div class="blend-mode">
    <p class="multiply">正片叠底</p>
</div>
<style>
    .blend-mode {
        font-size: 24px;
        font-weight: 700;
        color: #ff0000;
        background: #00ff00;
    }
    p.multiply {
        mix-blend-mode: multiply;
    }
</style>

image.png

这里用代码实现一下正片叠底的计算公式,大家可以自行验证是否正确。

function multiply(color1, color2) {
    const r1 = parseInt(color1.slice(1, 3), 16);
    const g1 = parseInt(color1.slice(3, 5), 16);
    const b1 = parseInt(color1.slice(5, 7), 16);
    const r2 = parseInt(color2.slice(1, 3), 16);
    const g2 = parseInt(color2.slice(3, 5), 16);
    const b2 = parseInt(color2.slice(5, 7), 16);
    const r = Math.round((r1 * r2) / 255);
    const g = Math.round((g1 * g2) / 255);
    const b = Math.round((b1 * b2) / 255);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(multiply('#ff0000', '#00ff00')); // #000

滤色


滤色的作用是将两个图层的之间的颜色叠加,使其产生一种比较明亮的效果。


滤色的效果计算相对来说要复杂一些,它的计算公式是:255 - ( (255-基色) * (255-混合色) ) / 255

例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#ffff00


这样就可以得到一个新的图像,它的像素点的色值为#ffff00


在CSS中我们可以通过mix-blend-mode: screen来实现这种效果。

/* 省略其他代码,同第一个示例代码相同 */
p.screen {
    mix-blend-mode: screen;
}

image.png

代码实现:

function screen(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = Math.round(255 - ((255 - r1) * (255 - r2)) / 255);
    const g = Math.round(255 - ((255 - g1) * (255 - g2)) / 255);
    const b = Math.round(255 - ((255 - b1) * (255 - b2)) / 255);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(screen('#00ff00', '#ff0000')); // #ffff0

在代码中基色指的是父元素的背景色,混合色指的是字体的颜色。


叠加


叠加的效果是将两个图层的颜色叠加,使其产生一种比较明亮的效果,如果底部的颜色比较明亮则减弱顶部的颜色,如果底部的颜色比较暗则增强顶部的颜色。


叠加的计算公式更加复杂了,它分两种情况:


  1. 如果基色小于等于128,则结果为:基色 * 混合色 / 128
  2. 如果基色大于128,则结果为:255 - ( (255-基色) * (255-混合色) ) / 128


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#00ff00


这样就可以得到一个新的图像,它的像素点的色值为#00ff00


在CSS中我们可以通过mix-blend-mode: overlay来实现这种效果。

p.overlay {
    mix-blend-mode: overlay;
}

image.png

代码实现:

function overlay(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = r1 <= 128 ? Math.round((r1 * r2) / 128) : Math.round(255 - ((255 - r1) * (255 - r2)) / 128);
    const g = g1 <= 128 ? Math.round((g1 * g2) / 128) : Math.round(255 - ((255 - g1) * (255 - g2)) / 128);
    const b = b1 <= 128 ? Math.round((b1 * b2) / 128) : Math.round(255 - ((255 - b1) * (255 - b2)) / 128);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(overlay('#00ff00', '#ff0000')); // #0ff0

变暗、


变暗的效果是将两个图层的颜色进行比较,如果混合色比基色暗,则使用混合色,否则使用基色。


变暗的计算公式是:基色和混合色中较小的那个会被保留,另一个会被抛弃。


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#000000


这样就可以得到一个新的图像,它的像素点的色值为#000000


在CSS中我们可以通过mix-blend-mode: darken来实现这种效果。

p.darken {
    mix-blend-mode: darken;
}

image.png

代码实现:

function darken(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = Math.min(r1, r2);
    const g = Math.min(g1, g2);
    const b = Math.min(b1, b2);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(darken('#ff0000', '#00ff00')); // #000

变亮


变亮和变暗正好相反。


变亮的计算公式是:基色和混合色中较大的那个会被保留,另一个会被抛弃。


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#ffff00


这样就可以得到一个新的图像,它的像素点的色值为#ffff00


在CSS中我们可以通过mix-blend-mode: lighten来实现这种效果。

p.lighten {
    mix-blend-mode: lighten;
}

image.png

代码实现:

function lighten(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = Math.max(r1, r2);
    const g = Math.max(g1, g2);
    const b = Math.max(b1, b2);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(lighten('#ff0000', '#00ff00')); // #ffff0

颜色减淡


颜色减淡的效果是将混合色的颜色添加到基色上,但是如果混合色的颜色比基色的颜色要深,则会使基色的颜色变浅。


颜色加深的计算公式是:基色 / (1 - 混合色)


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#00ff00


这样就可以得到一个新的图像,它的像素点的色值为#00ff00


在CSS中我们可以通过mix-blend-mode: color-dodge来实现这种效果。


p.color-dodge {
    mix-blend-mode: color-dodge;
}

image.png

代码实现:

function computed(Cb, Cs) {
    let B;
    if (Cb == 0) {
        B = 0;
    } else if (Cs == 1) {
        B = 1;
    } else {
        B = Math.min(1, Cb / (1 - Cs));
    }
    return Math.round(B * 255);
}
function colorDodge(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = computed(r1 / 255, r2 / 255);
    const g = computed(g1 / 255, g2 / 255);
    const b = computed(b1 / 255, b2 / 255);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(colorDodge('#00ff00', '#ff0000')); // #0ff0

这次的公式有点奇怪,1 代表 255,0 代表 0,因为我找了很多资料,这个公式是靠谱的,所以就沿用0和1的计算方式。


颜色加深


颜色加深的效果是将混合色的颜色添加到基色上,但是如果混合色的颜色比基色的颜色要浅,则会使基色的颜色变深。


颜色加深的计算公式是:1 - (1 - 基色) / 混合色


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#000000


这样就可以得到一个新的图像,它的像素点的色值为#000000


在CSS中我们可以通过mix-blend-mode: color-burn来实现这种效果。

p.color-burn {
    mix-blend-mode: color-burn;
}

image.png

颜色加深的代码实现:

function computed(Cb, Cs) {
    let B;
    if (Cb == 1) {
        B = 1;
    } else if (Cs == 0) {
        B = 0;
    } else {
        B = Math.max(0, 1 - (1 - Cb) / Cs);
    }
    return Math.round(B * 255);
}
function colorBurn(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = computed(r1 / 255, r2 / 255);
    const g = computed(g1 / 255, g2 / 255);
    const b = computed(b1 / 255, b2 / 255);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(colorBurn('#00ff00', '#ff0000')); // #0ff0

强光


强光主要用于调整图像的对比度和亮度,当混合色比较亮时,强光模式会让图像更亮,反之则会让图像变暗。


强光的计算公式是:混合色 < 0.5 ? 2 * 基色 * 混合色 : 1 - 2 * (1 - 基色) * (1 - 混合色)


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#ff0000


这样就可以得到一个新的图像,它的像素点的色值为#ff0000


在CSS中我们可以通过mix-blend-mode: hard-light来实现这种效果。

p.hard-light {
    mix-blend-mode: hard-light;
}

image.png

强光的代码实现:

function computed(Cb, Cs) {
    let B;
    if (Cs < 0.5) {
        B = 2 * Cb * Cs;
    } else {
        B = 1 - 2 * (1 - Cb) * (1 - Cs);
    }
    return Math.round(B * 255);
}
function hardLight(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = computed(r1 / 255, r2 / 255);
    const g = computed(g1 / 255, g2 / 255);
    const b = computed(b1 / 255, b2 / 255);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(hardLight('#00ff00', '#ff0000')); // #ff00

柔光


在柔光模式下,如果顶部图层的像素颜色值比底部图层的像素颜色值大,则将其混合到底部图层中;反之,则减少底部图层的亮度。


柔光的计算公式是:混合色 < 0.5 ? 2 * 基色 * 混合色 + 基色 * 基色 * (1 - 2 * 混合色) : sqrt(基色) * (2 * 混合色 - 1) + 2 * 基色 * (1 - 混合色)


例如两个图像的像素点的色值分别为:


  • 混合色:#ff0000
  • 基色:#00ff00
  • 结果:#00ff00


这样就可以得到一个新的图像,它的像素点的色值为#00ff00

image.png

柔光的代码实现:

function computed(Cb, Cs) {
    let B;
    if (Cs < 0.5) {
        B = 2 * Cb * Cs + Cb * Cb * (1 - 2 * Cs);
    } else {
        B = Math.sqrt(Cb) * (2 * Cs - 1) + 2 * Cb * (1 - Cs);
    }
    return Math.round(B * 255);
}
function softLight(baseColor, blendColor) {
    const r1 = parseInt(baseColor.slice(1, 3), 16);
    const g1 = parseInt(baseColor.slice(3, 5), 16);
    const b1 = parseInt(baseColor.slice(5, 7), 16);
    const r2 = parseInt(blendColor.slice(1, 3), 16);
    const g2 = parseInt(blendColor.slice(3, 5), 16);
    const b2 = parseInt(blendColor.slice(5, 7), 16);
    const r = computed(r1 / 255, r2 / 255);
    const g = computed(g1 / 255, g2 / 255);
    const b = computed(b1 / 255, b2 / 255);
    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
}
console.log(softLight('#00ff00', '#ff0000')); // #0ff0

差值


排除


色相


饱和度


颜色


亮度


写累了,不想写了,有兴趣的可以自己去实现一下,这些都在规范里面有:ltblendmodegt


后面几个感兴趣的可以自己动手来实现一下代码,这里就不写了。


使用


其实上面的原理没多少会喜欢,大家还是喜欢看实际的效果,那么我们就来看看这些混合模式的实际效果。

首先我上面的示例都是作用在文本上的,实际这些混合模式是可以作用在任何元素上的,比如图片,背景等等。


并且这些元素都是会作为叠加层来进行混合的,也就是说,如果你的元素有背景色,那么这个背景色也会参与到混合中,只要对顶层元素设置了混合模式,那么它的背景色也会参与到混合中。


我们来看看字体颜色与背景色的叠加,这个是最简单的,我们只需要设置一个背景色,然后设置一个字体颜色,然后设置一个混合模式就可以了。


<div class="blend-mode">
    <span>A</span>
    <span>B</span>
    <span>C</span>
    <span>D</span>
</div>
<style>
    .blend-mode {
        width: 200px;
        padding: 20px;
        font-weight: 700;
        font-size: 80px;
        letter-spacing: -.3em;
        text-align: center;
        color: #ff0000;
        background: linear-gradient(45deg, #F53F3F, #F77234, #FF7D00, #F7BA1E, #FADC19, #9FDB1D, #00B42A, #14C9C9, #3491FA, #165DFF, #722ED1);
    }
    .blend-mode span:nth-child(1) {
        color: #ff0000;
        mix-blend-mode: multiply;
    }
    .blend-mode span:nth-child(2) {
        color: #ffff00;
        mix-blend-mode: difference;
    }
    .blend-mode span:nth-child(3) {
        color: #00ff00;
        mix-blend-mode: color-dodge;
    }
    .blend-mode span:nth-child(4) {
        color: #0000ff;
        mix-blend-mode: screen;
    }
</style>

image.png

可以看到这样的叠加效果是非常有趣的,这里我只是用了四种混合模式,可以根据自己的需要进行搭配和选择。


我上面的效果虽然说还算可以,但是并没有那么有趣,那就随随便便加点动画,好像突然就变的有趣起来了:

.blend-mode span {
    display: inline-block;
}
.blend-mode span:nth-child(1) {
    color: #ff0000;
    mix-blend-mode: multiply;
    animation: shake 1.3s infinite alternate;
    animation-delay: .3s;
}
.blend-mode span:nth-child(2) {
    color: #ffff00;
    mix-blend-mode: difference;
    animation: shake 1s infinite alternate;
    animation-delay: .6s;
}
.blend-mode span:nth-child(3) {
    color: #00ff00;
    mix-blend-mode: color-dodge;
    animation: shake 1.5s infinite alternate;
    animation-delay: .9s;
}
.blend-mode span:nth-child(4) {
    color: #0000ff;
    mix-blend-mode: screen;
    animation: shake 2s infinite alternate;
    animation-delay: 1.2s;
}
@keyframes shake {
    0% {
        transform: translate(0, -10px);
        color: #3491FA;
    }
    20% {
        color: #722ED1;
    }
    40% {
        color: #F5319D;
    }
    60% {
        color: #A0C95E;
    }
    80% {
        color: #EBD89A;
    }
    100% {
        transform: translate(0, 20px);
    }
}

总结


mix-blend-mode是一个非常有趣的属性,也是非常强大的一个属性,它可以让我们的元素有更多的表现力,让我们的元素更加有趣,更加有生命力。


我上面的案例都是使用的文字相关的效果,但是这个属性并不仅仅局限于文字,它可以作用在任何元素上,比如图片,背景等等,只要对顶层元素设置了混合模式,那么它的背景色也会参与到混合中。


这个属性的兼容性还是很好的,除了IE11以下的版本,其他的浏览器都是支持的,所以可以放心的使用。


目录
相关文章
|
2天前
|
前端开发 JavaScript
css之伪类hover改变自身、子元素、其他元素的样式
css之伪类hover改变自身、子元素、其他元素的样式
35 0
|
2天前
|
前端开发 JavaScript 开发者
CSS隐藏元素的N种方法,你知道哪一种最适合你?
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
1天前
|
前端开发
CSS元素隐藏的多种方式:让你轻松实现页面布局
CSS元素隐藏的多种方式:让你轻松实现页面布局
|
1天前
|
前端开发
css中如何解决绝对定位元素被遮挡的问题
css中如何解决绝对定位元素被遮挡的问题
14 3
|
2天前
|
存储 移动开发 JavaScript
jQuery 根据 css 类筛选 DOM 元素的代码
jQuery 根据 css 类筛选 DOM 元素的代码
16 1
|
2天前
|
前端开发
|
2天前
|
前端开发
【Web前端】CSS基本语法规范和引入方式&&常见选择器用法&&常见元素属性
【Web前端】CSS基本语法规范和引入方式&&常见选择器用法&&常见元素属性
|
2天前
|
前端开发 开发者
【专栏:CSS基础篇】CSS选择器详解:精准定位网页元素
【4月更文挑战第30天】本文介绍了CSS选择器在Web开发中的重要性,详细阐述了基础选择器(元素、类、ID、属性和伪类/伪元素)及复杂选择器(后代、子元素、相邻兄弟和一般兄弟)的用法。通过理解并巧妙运用这些选择器,开发者能更高效地控制页面样式,提高代码的可维护性。CSS预处理器如Sass、LESS进一步增强了选择器的功能,助力创建优雅且强大的样式表,实现精准的网页设计。
|
2天前
|
前端开发 容器
css样式元素的相对定位,绝对定位,固定定位等元素定位运用技巧详解
css样式元素的相对定位,绝对定位,固定定位等元素定位运用技巧详解
|
2天前
|
前端开发 UED 开发者
【专栏】探讨了CSS3动画卡顿的原因,包括复杂动画效果、过多元素参与、低效代码结构和硬件资源限制,并提出优化措施
【4月更文挑战第29天】本文探讨了CSS3动画卡顿的原因,包括复杂动画效果、过多元素参与、低效代码结构和硬件资源限制,并提出优化措施:简化动画路径、控制元素数量、优化代码结构、利用硬件加速及性能监测。通过实际案例展示了优化效果,强调了性能优化对提升用户体验的重要性。在开发中,应持续关注并优化动画性能,以适应网页应用的需求。