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


目录
相关文章
|
9天前
|
前端开发 JavaScript
如何利用 CSS3 动画实现元素的淡入淡出效果?
在上述代码中,定义了一个名为 `fade-in` 的CSS类,其初始透明度为0,并设置了淡入的过渡效果。当通过JavaScript为元素添加 `active` 类时,元素的透明度变为1,实现淡入效果;当再次点击按钮移除 `active` 类时,元素又会逐渐淡出。通过这种方式,可以根据用户的操作灵活地控制元素的淡入淡出效果。
60 3
|
26天前
CSS_定位_网页布局总结_元素的显示与隐藏
CSS_定位_网页布局总结_元素的显示与隐藏
25 0
|
1月前
|
前端开发
css 块元素、行内元素、行内块元素相互转换
css 块元素、行内元素、行内块元素相互转换
124 0
|
1月前
|
前端开发 容器
CSS实现旋转圆角叠加样式,你学会了吗?
CSS实现旋转圆角叠加样式,你学会了吗?
36 0
|
3月前
|
前端开发 容器
最新CSS3定位元素
【8月更文挑战第28天】
29 5
|
3月前
|
前端开发
CSS - 使用 clip-path 轻松实现正六边形块状元素
如何使用CSS的`clip-path`属性来创建正六边形的块状元素。文章提供了详细的HTML和CSS代码示例,展示了如何实现六边形的布局和样式,并通过CSS动画增强了视觉效果。最终效果是一个包含文本的可交互的正六边形元素,当鼠标悬停时会改变颜色。
154 0
CSS - 使用 clip-path 轻松实现正六边形块状元素
|
3月前
|
存储 前端开发
为 HTML 元素指定 CSS 样式的方式
【8月更文挑战第24天】
75 0
|
3月前
|
前端开发
CSS动画新潮流:炫酷水波效果,让网页元素生动起来!
CSS动画新潮流:炫酷水波效果,让网页元素生动起来!
|
4月前
|
前端开发 容器
CSS对行级元素的影响
【7月更文挑战第4天】CSS对行级元素的影响
36 2
|
4月前
|
前端开发
css实用技巧——绝对定位元素的水平垂直居中
css实用技巧——绝对定位元素的水平垂直居中
49 2

热门文章

最新文章