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以下的版本,其他的浏览器都是支持的,所以可以放心的使用。


目录
相关文章
|
24天前
|
前端开发 JavaScript 开发者
CSS隐藏元素的N种方法,你知道哪一种最适合你?
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
1月前
|
前端开发 小程序
CSS元素居中大全
CSS元素居中大全
|
2月前
|
前端开发 JavaScript
如何利用jQuery来向一个元素中添加和移除CSS类?
如何利用jQuery来向一个元素中添加和移除CSS类?
20 0
|
3月前
|
前端开发 开发者
CSS必学:元素之间的空白与行内块的幽灵空白问题
CSS空白现象就是非常常见的问题之一。虽然它已经被发现很久,但仍然有许多新手和经验丰富的开发者们忽略了它对页面布局的影响。我们一起来看看吧!
45 4
CSS必学:元素之间的空白与行内块的幽灵空白问题
|
5天前
|
Web App开发 存储 前端开发
【JavaEE初阶】 CSS相关属性,元素显示模式,盒模型,弹性布局,Chrome 调试工具||相关讲解
【JavaEE初阶】 CSS相关属性,元素显示模式,盒模型,弹性布局,Chrome 调试工具||相关讲解
|
21天前
|
移动开发 前端开发 JavaScript
H5+CSS3+JS逆向前置——HTML1、H5文本元素
H5+CSS3+JS逆向前置——HTML1、H5文本元素
16 0
|
1月前
|
前端开发
【CSS】<Cascading Style Sheets>元素浮动&元素定位
【1月更文挑战第17天】【CSS】<Cascading Style Sheets>元素浮动&元素定位
|
1月前
|
前端开发 容器
CSS:元素显示模式与背景
CSS:元素显示模式与背景
26 0
|
1月前
|
前端开发 Java C++
面试官:用 CSS 实现一个元素的水平垂直居中,写出你能想到的所有答案
面试官:用 CSS 实现一个元素的水平垂直居中,写出你能想到的所有答案
|
1月前
|
前端开发
CSS z-index:元素堆叠
CSS z-index:元素堆叠
19 2

相关产品