首页 > web前端 > css教程 > 驯服混合模式:'差异和`excrusion'

驯服混合模式:'差异和`excrusion'

尊渡假赌尊渡假赌尊渡假赌
发布: 2025-03-26 10:53:14
原创
768 人浏览过

驯服混合模式:差异和`excrusion

直到2020年,混合模式才是我使用的功能,因为我很少知道他们可以在不先尝试一下就可以产生什么结果。并采取“尝试并了解发生了什么”的方法似乎总是让我对我在屏幕上创建的视觉呕吐物感到震惊。

这个问题是由于并不真正知道它们如何在背部工作。我看到有关该主题的每篇文章几乎都是基于示例,与Photoshop或详细艺术描述的比较。我发现示例很棒,但是当您不知道如何在后面工作时,将一个好看的演示调整为可以实现您在脑海中拥有不同想法的事物,这将变得非常耗时,令人沮丧和最终徒劳的冒险。然后,对于来自技术背景的人来说,Photoshop比较几乎没有用。对我来说,冗长的艺术描述对我来说就像企鹅语。

因此,当我遇到规格时,我有一个灯泡的时刻,发现它还包括数学公式,该公式根据哪种混合模式起作用。这意味着我终于可以理解这些东西在背面的工作方式以及它真正有用的地方。现在我知道了,我将在一系列文章中分享这些知识。

今天,我们将重点介绍混合的通常如何工作,然后仔细研究两种有点相似的混合模式 - 差异和排除 - 最后,将其删除本文的肉,我们将在下面剖析一些酷炫的用例,例如下面的用例。

让我们讨论混合模式的“如何”

混合意味着将两个层(将一个层堆叠在另一层上)并获得单层。这两个层可能是两个兄弟姐妹,在这种情况下,我们使用的CSS属性是混合模式。它们也可能是两个背景层,在这种情况下,我们使用的CSS属性是背景融合模式。请注意,当我谈论混合“兄弟姐妹”时,这包括将元素与伪元素或文本内容或父母的背景混合在一起。当涉及背景层时,不仅是我正在谈论的背景图像层 - 背景色也是一层。

混合两层时,顶部的图层称为,而下面的层则称为目的地。这是我所做的,因为这些名称至少对我来说没有多大意义。我希望目的地是输出,但它们既是输入,又是结果层是输出。

我们如何将这两层结合在一起取决于所使用的特定混合模式,但它总是每个像素。例如,下面的插图使用多重混合模式将两层(表示为像素网格)组合。

好吧,但是如果我们有两个以上的层,会发生什么?好吧,在这种情况下,混合过程从底部开始分阶段进行。

在第一阶段,底部的第二层是我们的源头,而底部的第一层是我们的目的地。这两个层混合在一起,结果成为第二阶段的目的地,其中底部的第三层是源。将第三层与前两个混合的结果融合为第三阶段的目的地,其中第四层从底部是源。

当然,我们可以在每个阶段使用不同的混合模式。例如,我们可以使用差异将前两层从底部融合在一起,然后使用乘数将结果与第三层从底部融合在一起。但这是我们在以后的文章中的更多信息。

我们在此处讨论的两个混合模式产生的结果不取决于两个层中的哪个在顶部。请注意,对于所有可能的混合模式而言,并非如此,但对于我们在本文中查看的情况是这种情况。

它们也是可分离的混合模式,这意味着分别在每个通道上执行混合操作。同样,对于所有可能的混合模式而言,并不是这种情况,但差异和排除就是这种情况。

更确切地说,所得的红色通道仅取决于源的红色通道和目的地的红色通道。所得的绿色通道仅取决于源的绿色通道和目的地的绿色通道。最后,所得的蓝色通道仅取决于源的蓝色通道和目的地的蓝色通道。

 r = f <sub>b</sub> (r <sub>s</sub> ,r <sub>d</sub> )
g = f <sub>b</sub> (g <sub>s</sub> ,g <sub>d</sub> )
b = f <sub>b</sub> (b <sub>s</sub> ,b <sub>d</sub> )
登录后复制

对于通用通道,未指定它是红色,绿色还是蓝色,我们的函数是源(顶部)层中的两个相应频道的函数,而目标(底部)层中的函数:

 ch = f <sub>b</sub> (ch <sub>s</sub> ,ch <sub>d</sub> )
登录后复制

要记住的是,RGB值可以在[0,255]间隔中表示,或在[0%,100%]间隔中以百分比表示,而我们在公式中实际使用的是表示为小数值的百分比。例如,深红色可以写为RGB(220、20、60)或RGB(86.3%,7.8%,23.5%) - 两者都是有效的。如果像素为深红色,我们用于计算的通道值是表示为十进制值的百分比,即.863,.078,.235。

如果像素是黑色的,则我们用于计算的通道值全部为0,因为黑色可以写为RGB(0、0、0)或RGB(0%,0%,0%)。如果像素为白色,则我们用于计算的通道值全部为1,因为白色可以写为RGB(255、255、255)或RGB(100%,100%,100%)。

请注意,无论我们在任何地方具有完全透明度(等于0的α),结果与另一层相同。

不同之处

此混合模式的名称可能会提供有关混合函数F B ()的线索。结果是两层的相应通道值之间差的绝对值。

 ch = f <sub>b</sub> (ch <sub>s</sub> ,ch <sub>d</sub> )= | ch s -ch d |
登录后复制

首先,这意味着,如果这两个层中的相应像素具有相同的RGB值(即三个通道中的每个通道中的每个一个),结果层的像素为黑色,因为所有三个通道的差异均为0。

 ch <sub>s</sub> = ch <sub>d</sub>
ch = f <sub>b</sub> (ch <sub>s</sub> ,ch <sub>d</sub> )= | ch <sub>s</sub> -ch <sub>d</sub> | = 0
登录后复制

其次,由于任何正数和0叶之间差的绝对值不变,因此导致相应的结果像素具有与另一层像素相同的RGB值,如果层的像素为黑色(所有通道等于0)。

如果黑色像素在顶部(源)层中,则用我们的公式中的0代替其信道值给我们:

 ch = f <sub>b</sub> (0,ch <sub>d</sub> )= | 0 -ch <sub>d</sub> | = | -CH <sub>D</sub> | = ch <sub>d</sub>
登录后复制

如果黑色像素在底部(目的地)层中,则用我们的公式中的0代替其通道值给我们:

 ch = f <sub>b</sub> (ch <sub>s</sub> ,0)= | ch <sub>s</sub> -0 | = | ch <sub>s</sub> | = ch <sub>s</sub>
登录后复制

最后,由于任何阳性的亚基数和1之间差的绝对值为我们提供了该数字的补充,因此,如果层的像素是白色的(具有所有通道1),则相应的结果像素是另一个层的像素完全倒置(什么滤镜:extract:intervent:invert:invert(invert(1)将对它做)。

如果白色像素位于顶部(源)层,用我们的公式中的1代替其通道值给我们:

 ch = f <sub>b</sub> (1,ch <sub>d</sub> )= | 1 -ch <sub>d</sub> | = 1 -ch <sub>d</sub>
登录后复制

如果白色像素位于底部(目的地)层,则用我们的公式中的1代替其通道值给我们:

 ch = f <sub>b</sub> (ch <sub>s</sub> ,1)= | ch <sub>s</sub> -1 | = 1 -ch <sub>s</sub>
登录后复制

这可以在下面的交互式笔中看到,您可以在查看分离的层和查看它们重叠和混合之间切换。悬停在重叠情况下的三列也揭示了每个列的情况。

排除

对于今天我们要查看的第二个也是最后一个混合模式,结果是两个通道值的产物的两倍,从其总和中减去:

 ch = f <sub>b</sub> (ch <sub>s</sub> ,ch <sub>d</sub> )= ch s ch d -2·ch s ·ch d
登录后复制

由于两个值都在[0,1]间隔中,因此它们的产物最多等于最小的产品,因此产品的两倍始终最多等于其总和。

如果我们考虑顶部(源)层中的黑色像素,则在上面的公式中替换为0 ,我们将获得相应结果像素通道的以下结果:

 ch = f <sub>b</sub> (0,ch <sub>d</sub> )= 0 ch <sub>d</sub> -2·0·ch <sub>d</sub> = ch <sub>d</sub> -0 = ch <sub>d</sub>
登录后复制

如果我们考虑底部(目的地)层中的黑色像素,然后在上面的公式中替换为0 ,我们会为相应结果像素的通道获得以下结果:

 ch = f <sub>b</sub> (ch <sub>s</sub> ,0)= ch <sub>s</sub> 0-2·ch <sub>s</sub> ·0 = ch <sub>s</sub> -0 = ch <sub>s</sub>
登录后复制

因此,如果层的像素是黑色的,则结果使相应的结果像素与另一层的像素相同。

如果我们考虑顶部(源)层中的白色像素,则在上面的公式中用1替换Ch s ,我们将获得相应结果像素通道的以下结果:

 ch = f <sub>b</sub> (1,ch <sub>d</sub> )= 1 ch <sub>d</sub> -2·1·ch <sub>d</sub> = 1 ch <sub>d</sub> -2·ch <sub>d</sub> = 1 -ch <sub>d</sub>
登录后复制

如果我们考虑底部(目的地)层中的白色像素,然后在上面的公式中替换1个ch d ,我们将获得相应结果像素通道的以下结果:

 ch = f <sub>b</sub> (ch <sub>s</sub> ,1)= ch <sub>s</sub> 1-2·ch <sub>s</sub> ·1 = ch <sub>s</sub> 1-2·ch <sub>s</sub> = 1 -ch <sub>s</sub>
登录后复制

因此,如果层的像素是白色的,则结果使相应的结果像素与另一层的像素倒置相同。

这一切都显示在以下交互式演示中:

请注意,只要至少一个层仅具有黑白像素,差异和排除产生完全相同的结果。

现在,让我们转到混合模式的“什么”

这是有趣的部分 - 例子!

文本状态变化效果

假设我们有一个链接的段落:

 <p>你好,<a href="'%EF%BC%83'">世界</a>!</p>
登录后复制

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

身体 {
  显示:网格;
  位置盛口:中心;
  身高:100VH;
  背景:#222;
  颜色:#ddd;
  字体大小:夹具(1.25EM,15VW,7EM);
}

{颜色:黄金; }
登录后复制

到目前为止看起来还不算什么,但是我们很快就会改变这一点!

下一步是创建一个绝对定位的伪元素,涵盖整个链接,并将其背景设置为CurrentColor。

 a {
  位置:相对;
  颜色:黄金;
  
  &::后 {
    位置:绝对;
    顶部:0;
    底部:0;
    右:0;
    左:0;
    背景:CurrentColor;
    内容: '';
  }
}
登录后复制

以上看起来我们已经把事情搞砸了……但是我们真的吗?我们在这里拥有的是金文字的金矩形。而且,如果您关注上述两种混合模式如何工作,那么您可能已经猜到了下一步的内容 - 我们使用差异融合了链接中的两个兄弟姐妹节点(伪元素矩形和文本内容),并且由于它们都是金色的,因此它们都会导致他们的共同点 - 文本 - 文本 - 变成黑色。

 p {隔离:隔离; }

a {
  / *与以前相同 */
  
  &::后 {
    / *与以前相同 */
    混合模式:差异;
  }
}
登录后复制

请注意,我们必须隔离段落,以防止与身体背景混合。虽然这只是Firefox中的一个问题(鉴于我们在身体上的背景非常深,但它并不是太明显了),并且在Chrome中很好,请记住,根据规格,Firefox的作​​用实际上是正确的。在这里,Chrome以错误的方式行为,因此,如果错误修复了隔离,我们应该设置隔离属性。

好吧,但是我们希望只有在链接集中或徘徊时才会发生这种情况。否则,伪元素不可见 - 假设它的缩小为一无所有。

 a {
  / *与以前相同 */
  文本介绍:无;
  
  &::后 {
    / *与以前相同 */
    变换:比例(0);
  }

  &:focus {大纲:无}
  &:focus,&:hover {&:: after {transform:none; }}}
}
登录后复制

我们还删除了链接下划线和焦点大纲。下面,您现在可以看到悬停的差异效果(对以下效果发生相同的效果:焦点,这是可以在实时演示中测试的内容)。

现在,我们已经改变了状态,但看起来很粗糙,所以让我们添加一个过渡!

 a {
  / *与以前相同 */
  
  &::后 {
    / *与以前相同 */
    过渡:变换.25;
  }
}
登录后复制

更好!

如果我们的伪在中间什么都没有,而是从底部的细线中脱颖而出,那看起来会更好。这意味着我们需要将转换原始物质设置在底部边缘(以100%的垂直和水平价值为单位),并最初将我们的伪缩放到Y轴沿Y轴上的东西略重要。

 a {
  / *与以前相同 */
  
  &::后 {
    / *与以前相同 */
    转化原始:0 100%;
    变换:scaley(.05);
  }
}
登录后复制

我想在这里做的其他事情是将段落的字体替换为更具美感的字体,所以让我们也要照顾好款项!但是我们现在有一个不同的问题:“ D”的末尾伸出矩形:focus/:悬停。

我们可以在链接上使用水平填充来解决此问题。

 a {
  / *与以前相同 */
  填充:0 .25EM;
}
登录后复制

如果您想知道为什么我们在右侧和左侧都设置此填充物,而不仅仅是设置填充右侧,则在下面说明了原因。当我们的链接文本变成“外星世界”时,如果我们没有衬垫左侧,则“ A”的卷曲开始将在我们的矩形之外。

当我们减少视口宽度时,该演示具有多字链接,也重点介绍了另一个问题。

这里的一个快速修复是设置显示:链接上的内联块。这不是一个完美的解决方案。当链接文本比视口宽度更长时,它也会破裂,但是在这种特殊情况下它可以工作,所以现在就把它放在这里,我们将在一段时间内回到这个问题。

现在,让我们考虑一个光主题的情况。由于无法获得白色而不是黑色的链接文本上的链接文本:悬停或:通过混合两个相同的高光层,这些层都不是白色的,我们在这里需要一些不同的方法,一种不涉及仅使用混合模式的方法。

在这种情况下,我们要做的是首先设置背景,正常段落文本颜色以及链接文本颜色与我们想要的值但倒置。我最初是手动进行反转的,但是后来我得到了使用SASS Invert()函数的建议,这是一个非常酷的想法,可以真正简化事物。然后,在我们拥有这个深色主题之后,基本上是我们想要的光主题,我们通过在CSS Invert()滤波器功能的帮助下再次颠倒所有内容来获得所需的结果。

这里的小警告:我们无法设置过滤器:在身体或HTML元素上倒(1),因为这不会以我们期望的方式行事,也不会得到所需的结果。但是我们可以将背景和过滤器设置在段落周围的包装器上。

 
  <p>你好,<a href="'%EF%BC%83'">外星人世界</a>!</p>
登录后复制
身体 {
  /*与以前相同, 
     没有地点,背景和颜色声明, 
     我们在本节上移动 */
}

部分 {
  显示:网格;
  位置盛口:中心;
  背景:iNvert(#ddd) / * sass invert(<color>)函数 * /;
  颜色:反转(#222); / * SASS Invert <color>)函数 */;
  过滤器:反转(1); / * CSS过滤器倒置()函数 */
}

a {
  / *与以前相同 */
  颜色:反转(紫色); / * SASS Invert(<color>)函数 */
}</color></color></color>
登录后复制

这是采用此效果的导航栏的一个示例(以及其他许多聪明的技巧,但这些技巧都超出了本文的范围)。选择其他选项以在行动中查看它:

我们需要谨慎的其他事情是以下内容:使用此技术时,我们部分的所有后代都会倒置。在IMG元素的情况下,这可能不是我们想要的 - 当我从黑暗转换为轻型主题时,我当然不希望在博客文章中看到图像。因此,我们应该在我们部分的每个IMG后代上逆转过滤器反转。

部分 {
  / *与以前相同 */
  
  &&&img {filter:invert(1); }
}
登录后复制

将所有内容放在一起,下面的演示显示了带有图像的黑暗和光主题案例:

现在,让我们回到包装链接文本问题,看看我们没有比使A元素内联块的选项更好的选择。

好吧,我们愿意!我们可以混合两个背景层,而不是混合文本内容和伪。一层被剪裁到文本上,而另一层将其剪裁到边框盒中,其垂直尺寸最初在5%和100%的垂直尺寸中,在悬停的案例中100%。

 a {
  / *与以前相同 */
  -webkit-text-fill-color:透明;
     -moz-text填充色:透明;
  -Full:线性学位(CurrentColor,CurrentColor);
  背景: 
    var( - 完整), 
    var( - 完整)0 100%/1%var(-sy,5%)重复X;
  -webkit-background-clip:文本,边框框;
          背景折叠:文本,边框框;
  背景融合模式:差异;
  过渡:背景大小.25;
	
  &:焦点,&:悬停{ -  sy:100%; }
}
登录后复制

请注意,我们甚至不再有伪元素,因此我们将其中的一些CSS放在上面,将其移到链接本身上,并对其进行调整以适合这种新技术。我们已经从使用Mix-Blend模式转换为使用Background-Blend-Mode;现在,我们正在过渡转换的背景大小,在:焦点和悬停状态中;现在,我们不是更改转换,而是代表背景大小的垂直组件的自定义属性。

更好,尽管这也不是一个完美的解决方案。

第一个问题是,如果您在Firefox中检查了标题的实时演示链接,那么您肯定会注意到一个问题:它根本不起作用。这是由于我显然在2018年报告的Firefox错误,然后忘记了所有内容,直到我开始使用混合模式并再次击中它。

第二个问题是录音中引人注目的问题。链接似乎有些褪色。这是因为,出于某种原因,Chrome将内联元素(例如链接(请注意)(如Divs这样的块元素)与他们最近的祖先的背景(在这种情况下为部分),如果这些内线元素将背景 - 蓝模式设置为正常,则这些元素的背景(在这种情况下为部分)。

更奇怪的是,设置隔离:在链接或其父段上隔离并不能阻止这种情况的发生。我仍然有一种挑剔的感觉,它一定与上下文有关,所以我决定继续对此进行可能的黑客攻击,并希望有些事情最终可以起作用。好吧,我不必花很多时间在上面。将不透明度设置为一个统一(但仍然足够接近1个,因此并不明显它并不完全不透明)值可以修复它。

 a {
  / *与以前相同 */
  不透明:.999; / * hack以解决混合问题`_(ツ)_/ */
}
登录后复制

最后一个问题是录音中引人注目的另一个问题。如果您在“ Amur”的末端查看“ R”,您可能会注意到它的右端被切开,因为它落在背景矩形之外。如果您将其与“豹”中的“ r”进行比较,这一点尤其明显。

我对解决这个问题没有很高的希望,但无论如何都将问题扔到了Twitter上。您知道什么,可以解决!使用盒子破坏与我们已经设置的填充物结合使用可以帮助我们实现所需的效果!

 a {
  / *与以前相同 */
  盒子破裂:克隆;
}
登录后复制

请注意,Box-Decoration-Break仍然需要所有WebKit浏览器的-webkit-前缀,但是与诸如background-clip之类的属性不同,至少一个值是文本,自动排序工具可以很好地解决问题。这就是为什么我还没有在上面的代码中包含前缀版本的原因。

我得到的另一个建议是增加负距离以补偿填充物。我要在这个方面来回来回 - 我无法决定我是否更喜欢结果。无论如何,这是值得一提的选择。

 $ p:.25em;

a {
  / *与以前相同 */
  保证金:0( -  $ p); / *我们将其放在括号中,因此Sass不会尝试执行减法 */
  填充:0 $ P;
}
登录后复制

尽管如此,我不得不承认,仅对渐变的背景位置或背景大小进行动画有些无聊。但是,感谢Houdini,我们现在可以使我们希望的渐变中的任何组成部分都能发挥创造力,即使目前仅在Chromium中得到支持。例如,径向级别()的半径如下或圆锥级别的进度()。

仅倒元素(或背景)的区域

这是我经常看到通过使用元素重复来实现的效果 - 这两个副本是在另一个副本上层面上的,其中一个副本具有反转滤波器,并且在顶部使用夹子,以显示两层。另一条路线是将第二个元素分层,而α足够低,您甚至无法确定它在那里和背景过滤器。

这两种方法都可以完成工作,如果我们想将整个元素的所有内容和后代倒入一部分,但是当我们只想扭转背景的一部分时,它们就无法帮助我们 - 过滤器和背景过滤器都会影响整个元素,而不仅仅是其背景。虽然新的滤镜功能()函数(已由Safari支持)确实仅对背景层产生影响,但它会影响背景的整个区域,而不仅仅是其中的一部分。

这是混合进来的地方。该技术非常简单:我们有一个背景层,其中一部分是我们想要反转的,一个或多个梯度层为我们提供了一个白色区域,我们希望将另一层和透明度(或黑色)倒置为否则。然后,我们使用今天讨论的两种混合模式之一融合。出于反转的目的,我更喜欢排除(比差异短一个字符)。

这是第一个示例。我们有一个具有两层背景的正方形元素。这两层是猫的图片和梯度,白色和透明之间具有急剧过渡。

 div {
  背景: 
    线性毕业生(45度,白色50%,透明0), 
    URL(cat.jpg)50%/覆盖;
}
登录后复制

这给了我们以下结果。我们还设置了尺寸,边界 - 拉迪乌斯,阴影并在此过程中修饰了文本,但是在这种情况下,所有这些内容并不重要:

接下来,我们只需要另外一份CSS声明即可颠倒左下半部分:

 div {
  / *与以前相同 */
  背景融合模式:排除; / *或差异,但更长1个char */
}
登录后复制

请注意文本不受反转影响;它仅应用于背景。

您可能知道前后图像滑块的交互式。您甚至可能已经在CSS-tricks上看到了一些类似的东西。我在Compressor.io上看到了它,我经常用来压缩图像,包括这些文章中使用的图像!

我们的目标是使用单个HTML元素(100个字节的JavaScript)创建类型的东西,甚至没有太多的CSS!

我们的元素将是范围输入。我们不设置其最小属性或最大属性,因此它们分别默认为0和100。我们也不设置值属性,因此默认为50,这也是我们给出的自定义属性-k,以其样式属性设置的值。

 
登录后复制

在CSS中,我们从基本的重置开始,然后使输入成为占据整个视口高的块元素。我们还为其轨道和拇指提供了尺寸和虚拟背景,以便我们可以立即在屏幕上看到东西。

 $ thumb-w:5em;

@mixin track(){
  边界:无;
  宽度:100%;
  身高:100%;
  背景:URL(Flowers.jpg)50%/覆盖;
}

@mixin thumb(){
  边界:无;
  宽度:$ thumb-w;
  身高:100%;
  背景:紫色;
}

* {
  保证金:0;
  填充:0;
}

[type ='range'] {
  &&::  -  webkit-slider-thumb, 
  &::  -  webkit-slider-runnable-track {-webkit-appearance:none; }
  
  显示:块;
  宽度:100VW;身高:100VH;
  
  &::  -  webkit-slider-runnable-track {@include track; }
  &::  -  moz-range-track {@include track; }
  
  &::  -  webkit-slider-thumb {@include thumb; }
  &::  -  moz-range-thumb {@include thumb; }
}
登录后复制

下一步是在轨道上添加另一个背景图,这是一个线性梯度,其中透明和白色之间的分离线取决于当前范围输入值-K,然后将两者混合在一起。

 @mixin track(){
  / *与以前相同 */
  背景:
    URL(flowers.jpg)50%/覆盖, 
    线性梯度(90摄氏度,透明var(-p),白色0);
  背景融合模式:排除;
}

[type ='range'] {
  / *与以前相同 */
  -p:calc(var(-k) * 1%);
}
登录后复制

请注意,轨道的两个背景层的顺序并不重要,因为排除和差异都是交换性的。

它开始看起来像某物,但是拖动拇指无助于移动分离线。之所以发生这种情况,是因为当前值-K(梯度的分离线位置-p,依赖)不会自动更新。让我们用一点点的JavaScript修复,该JavaScript只要更改时就会获得滑块值,然后将其设置为-K到此值。

 AddEventListener('输入',e => {
  令_t = e.target;
  _t.style.setproperty(' -  k',_t.value)
}))
登录后复制

现在一切似乎都很好!

但是真的吗?假设我们为拇指背景做一些更喜欢的事情:

 $ thumb-r:.5*$ thumb-w;
$ thumb-l:2px;

@mixin thumb(){
  / *与以前相同 */
   - 名单:#FFF 0%60DEG,透明0%;
  背景: 
    圆锥分子(来自60deg,var( -  list))0/37.5%/ *左箭头 */, 
    圆锥级别(来自240DEG,var( - 列表))100%/37.5%/ *正确的箭头 */, 
    径向梯度(圆, 
      透明的计算(#{$ thumb -r}  - #{$ thumb -l} -1px) / *内部圆 * /, 
      #fff calc(#{$ thumb-r}  - #{$ thumb-l})calc(#{$ {$ thumb-r}  -  1px) / * circle line * /,, 
      透明$ thumb-r / *外圆 * /), 
    线性梯度(
      #fff calc(50% - #{$ thumb-r} .5*#{$ thumb-l}) /*top Line* /, 
      透明0 calc(50%#{$ thumb-r}  -  .5*#{$ thumb-l}) /*circle后面的差距* /, 
      #FFF 0/ *底线 */)50%0/#{$ thumb-l};
  背景重复:无重复;
}
登录后复制

线性级别()创建薄的垂直分离线,径向级别()创建圆,而两个圆锥级别()层产生箭头。

现在,当将拇指从一端拖到另一端时,问题很明显:分离线并不能保持拇指的垂直中线。

当我们设置为-p calc(var(-k)*1%)时,分离线从0%移动到100%。它确实应该从一个拇指宽度的起点($ thumb-r)移动,直到100%之前的拇指宽度为一半。也就是说,在100%减去拇指宽度的范围内,$ thumb-w。我们从两端减去一半,因此这是要减去的整个拇指宽度。让我们解决这个问题!

 -p:calc(#{$ thumb-r} var(-k) *(100% - #{$ thumb-w}) / 100);
登录后复制

更好!

但是,范围输入的方式是,其边框框在曲目的内容框(Chrome)的范围内或实际输入的内容框(Firefox)的范围内移动……这仍然感觉不正确。如果拇指的中线(因此,分离线)一直到视口边缘,那看起来会更好。

我们无法更改范围输入的工作方式,但是我们可以使输入在视口外扩展到左侧的一半拇指宽度,然后向右向右的一半拇指宽度。这使其宽度等于视口的宽度,100VW,以及整个拇指宽度,$ thumb-w。

身体{溢出:隐藏; }

[type ='range'] {
  / *与以前相同 */
  左键: -  $ thumb-r;
  宽度:calc(100vw#{$ thumb-w});
}
登录后复制

还有一些与光标有关的修改,仅此而已!

此版本的更奇特的版本(灵感来自Compressor.io网站)是将输入放入卡中,其3D旋转在鼠标移动时也会发生变化。

我们还可以使用垂直滑块。这是一个稍微复杂的,因为我们唯一可靠的跨浏览器方式来创建自定义样式的垂直滑块是在它们上施加旋转,但这也将旋转背景。我们要做的是设置-p值,并在(未旋转)滑块容器上设置这些背景,然后将输入及其轨道完全透明。

这可以在下面的演示中看到,在那里,我正在颠倒我炫耀我心爱的Kreator连帽衫的照片。

当然,我们也可以使用径向级别()来产生很酷的效果:

背景: 
  径向梯度(circle( -  x,50%)var(-y,50%), 
    #000 calc(var(-card-r)-1px),#fff var(-card-r))边框框, 
  $ IMG 50%/封面;
登录后复制

在这种情况下,从卡上的鼠标运动中计算出-X和-Y自定义属性给出的位置。

背景的倒置区域不一定是由梯度创建的。正如这篇较旧的文章与背景图像相比的旧文章所示,它也可以是标题文本背后的区域。

逐渐反转

反转的混合技术比以多种方式使用过滤器更强大。它还使我们能够沿梯度逐渐应用效果。例如,左侧根本没有反转,但是我们一直向右前进到完整的反转。

为了了解如何获得这种效果,我们必须首先了解如何获得倒置(P)效应,其中P可以是[0%,100%]间隔中的任何值(或在[0,1]间隔中,如果使用小数小数表示)。

第一种用于差异和排除的方法是设置白色至p的alpha通道。这可以在下面的演示中看到,在下面的演示中,拖动滑块控制着Invrsion的进度:

如果您想知道HSL(0,0%,100% / 100%)符号,现在这是一种有效的方式,可以表示白色,其alpha为1。

此外,由于滤波器的方式:iNvert(p)在一般情况下起作用(即,将每个通道值缩放到挤压间隔[min(p,q),max(p,q)]),其中q是p(或q = 1-p)的补充,然后倒入1(从1中扣除1),我们有以下一般的通道CH,一定要在一部分通道CH上进行。

 1-(Q ch·(p -q))= 
= 1-(1 -p ch·(p  - (1- p)))= 
= 1-(1 -P ch·(2·P -1))= 
= 1-(1- P 2·Ch·P- ch)= 
= 1-1 p -2·ch·P ch = 
= ch p -2·ch·P
登录后复制

我们得到的正是在另一个频道为p的情况下排除的公式!因此,我们可以通过使用排除混合模式在[0%,100%]间隔中的任何P中获得与过滤器相同的效果:当另一层为RGB时(p,p,p,p)时。

这意味着我们可以沿着线性级别()逐渐反转,该线性梯度()从沿左边缘的无反转到右边缘的完整反转),如下:

背景: 
  URL(butterfly_blues.jpg)50%/封面, 
  线性梯度(90级, 
    #000 / *相当于RGB(0%,0%,0%)和HSL(0,0%,0%) * /, 
    #FFF / *相当于RGB(100%,100%,100%)和HSL(0,0%,100%) * /);
背景融合模式:排除;
登录后复制

请注意,使用从黑色到白色的梯度进行逐渐反演,仅适用于排除混合模式,而不是差异。鉴于其公式,在这种情况下差异产生的结果是伪逐渐反演,中间不会通过50%的灰色,而是通过将三个通道沿梯度沿各个点零的三个通道中的每个通道中的每个通道中的每个通道传递出来。这就是为什么对比度看起来很鲜明的原因。这也许也有些艺术性,但这并不是我有资格对此有意见的意见。

在背景上具有不同级别的反转,不一定需要从黑色到白色梯度。它也可以来自黑白图像,因为图像的黑色区域将保留背景色,白色区域将完全反转,并且在使用排除混合模式时,我们将对所有之间的一切都进行部分反转。差异将再次给我们带来Starker Duotone的结果。

这可以在以下交互式演示中看到,您可以在其中更改背景色,并在两个混合模式产生的结果之间拖动分离线。

空心交叉效应

The basic idea here is we have two layers with only black and white pixels.

Ripples and rays

Let's consider an element with two pseudos, each having a background that's a repeating CSS gradient with sharp stops:

 $d: 15em;
$u0: 10%;
$u1: 20%;

div {
  &::before, &::after {
    显示:内联块;
    width: $d;
    height: $d;
    background: repeating-radial-gradient(#000 0 $u0, #fff 0 2*$u0);
    内容: '';
  }
  
  &::后 {
    background: repeating-conic-gradient(#000 0% $u1, #fff 0% 2*$u1);
  }
}
登录后复制

Depending on the browser and the display, the edges between black and white may look jagged… or not.

Just to be on the safe side, we can tweak our gradients to get rid of this issue by leaving a tiny distance, $e, between the black and the white:

 $u0: 10%;
$e0: 1px;
$u1: 5%;
$e1: .2%;

div {
  &::前 {
    背景: 
      repeating-radial-gradient(
        #000 0 calc(#{$u0} - #{$e0}), 
        #fff $u0 calc(#{2*$u0} - #{$e0}), 
        #000 2*$u0);
  }
  
  &::后 {
    背景: 
      repeating-conic-gradient(
        #000 0% $u1 - $e1, 
        #fff $u1 2*$u1 - $e1, 
        #000 2*$u1);
  }
}
登录后复制

Then we can place them one on top of the other and set mix-blend-mode to exclusion or difference, as they both produce the same result here.

 div {
  &::before, &::after {
    /* same other styles minus the now redundant display */
    位置:绝对;
    mix-blend-mode: exclusion;
  }
}
登录后复制

Wherever the top layer is black, the result of the blending operation is identical to the other layer, whether that's black or white. So, black over black produces black, while black over white produces white.

Wherever the top layer is white, the result of the blending operation is identical to the other layer inverted. So, white over black produces white (black inverted), while white over white produces black (white inverted).

However, depending on the browser, the actual result we see may look as desired (Chromium) or like the ::before got blended with the greyish background we've set on the body and then the result blended with the ::after (Firefox, Safari).

The way Chromium behaves is a bug, but that's the result we want. And we can get it in Firefox and Safari, too, by either setting the isolation property to isolate on the parent div (demo) or by removing the mix-blend-mode declaration from the ::before (as this would ensure the blending operation between it and the body remains the default normal, which means no blending) and only setting it on the ::after (demo).

Of course, we can also simplify things and make the two blended layers be background layers on the element instead of its pseudos. This also means switching from mix-blend-mode to background-blend-mode.

 $d: 15em;
$u0: 10%;
$e0: 1px;
$u1: 5%;
$e1: .2%;

div {
  width: $d;
  height: $d;
  背景: 
    repeating-radial-gradient(
      #000 0 calc(#{$u0} - #{$e0}), 
      #fff $u0 calc(#{2*$u0} - #{$e0}), 
      #000 2*$u0), 
    repeating-conic-gradient(
      #000 0% $u1 - $e1, 
      #fff $u1 2*$u1 - $e1, 
      #000 2*$u1);;
  background-blend-mode: exclusion;
}
登录后复制

This gives us the exact same visual result, but eliminates the need for pseudo-elements, eliminates the potential unwanted mix-blend-mode side effect in Firefox and Safari, and reduces the amount of CSS we need to write.

分屏

The basic idea is we have a scene that's half black and half white, and a white item moving from one side to the other. The item layer and the scene layer get then blended using either difference or exclusion (they both produce the same result).

When the item is, for example, a ball, the simplest way to achieve this result is to use a radial-gradient for it and a linear-gradient for the scene and then animate the background-position to make the ball oscillate.

 $d: 15em;

div {
  width: $d;
  height: $d;
  背景: 
    radial-gradient(closest-side, #fff calc(100% - 1px), transparent) 
      0/ 25% 25% no-repeat,
    linear-gradient(90deg, #000 50%, #fff 0);
  background-blend-mode: exclusion;
  animation: mov 2s ease-in-out infinite alternate;
}

@keyframes mov { to { background-position: 100%; } }
登录后复制

We can also make the ::before pseudo the scene and the ::after the moving item:

 $d: 15em;

div {
  display: grid;
  width: $d;
  height: $d;
  
  &::before, &::after {
    grid-area: 1/ 1;
    background: linear-gradient(90deg, #000 50%, #fff 0);
    内容: '';
  }
  
  &::后 {
    place-self: center start;
    padding: 12.5%;
    边界拉迪乌斯:50%;
    背景:#fff;
    mix-blend-mode: exclusion;
    animation: mov 2s ease-in-out infinite alternate;
  }
}

@keyframes mov { to { transform: translate(300%); } }
登录后复制

This may look like we're over-complicating things considering that we're getting the same visual result, but it's actually what we need to do if the moving item isn't just a disc, but a more complex shape, and the motion isn't just limited to oscillation, but it also has a rotation and a scaling component.

 $d: 15em;
$t: 1s;

div {
  /* same as before */
  
  &::后 {
    /* same as before */
    /* creating the shape, not detailed here as
       it's outside the scope of this article */
    @include poly;
    /* the animations */
    动画片: 
      t $t ease-in-out infinite alternate, 
      r 2*$t ease-in-out infinite, 
      s .5*$t ease-in-out infinite alternate;
  }
}

@keyframes t { to { translate: 300% } }
@keyframes r {
  50% { rotate: .5turn; }
  100% { rotate: 1turn;; }
}
@keyframes s { to { scale: .75 1.25 } }
登录后复制

Note that, while Safari has now joined Firefox in supporting the individual transform properties we're animating here, these are still behind the Experimental Web Platform features flag in Chrome (which can be enabled from chrome://flags as shown below).

More examples

We won't be going into details about the “how” behind these demos as the basic idea of the blending effect using exclusion or difference is the same as before and the geometry/animation parts are outside the scope of this article. However, for each of the examples below, there is a link to a CodePen demo in the caption and a lot of these Pens also come with a recording of me coding them from scratch.

Here's a crossing bars animation I recently made after a Bees & Bombs GIF:

And here's a looping moons animation from a few years back, also coded after a Bees & Bombs GIF:

We're not necessarily limited to just black and white. Using a contrast filter with a subunitary value (filter: contrast(.65) in the example below) on a wrapper, we can turn the black into a dark grey and the white into a light grey:

Here's another example of the same technique:

If we want to make it look like we have a XOR effect between black shapes on a white background, we can use filter: invert(1) on the wrappers of the shapes, like in the example below:

And if we want something milder like dark grey shapes on a light grey background, we don't go for full inversion, but only for partial one. This means using a subunitary value for the invert filter like in the example below where we use filter: invert(.85):

It doesn't necessarily have to be something like a looping or loading animation. We can also have a XOR effect between an element's background and its offset frame. Just like in the previous examples, we use CSS filter inversion if we want the background and the frame to be black and their intersection to be white.

Another example would be having a XOR effect on hovering/ focusing and clicking a close button. The example below shows both night and light theme cases:

给我生命

Things can look a bit sad only in black and white, so there are few things we can do to put some life into such demos.

The first tactic would be to use filters. We can break free from the black and white constraint by using sepia() after lowering the contrast (as this function has no effect over pure black or white). Pick the hue using hue-rotate() and then fine tune the result using brightness() and saturate() or contrast().

For example, taking one of the previous black and white demos, we could have the following filter chain on the wrapper:

筛选: 
  contrast(.65) /* turn black and white to greys */
  sepia(1) /* retro yellow-brownish tint */
  hue-rotate(215deg) /* change hue from yellow-brownish to purple */
  blur(.5px) /* keep edges from getting rough/ jagged */
  contrast(1.5) /* increase saturation */
  brightness(5) /* really brighten background */
  contrast(.75); /* make triangles less bright (turn bright white dirty) */
登录后复制

For even more control over the result, there's always the option of using SVG filters.

The second tactic would be to add another layer, one that's not black and white. For example, in this radioactive pie demo I made for the first CodePen challenge of March, I used a purple ::before pseudo-element on the body that I blended with the pie wrapper.

 body, div { display: grid; }

/* stack up everything in one grid cell */
div, ::before { grid-area: 1/ 1; }

body::before { background: #7a32ce; } /* purple layer */

/* applies to both pie slices and the wrapper */
div { mix-blend-mode: exclusion; }

.a2d { background: #000; } /* black wrapper */

.pie {
  background: /* variable size white pie slices */
    conic-gradient(from calc(var(--p)*(90deg - .5*var(--sa)) - 1deg), 
      透明的, 
      #fff 1deg calc(var(--sa) var(--q)*(1turn - var(--sa))), 
      transparent calc(var(--sa) var(--q)*(1turn - var(--sa)) 1deg));
}
登录后复制

This turns the black wrapper purple and the white parts green (which is purple inverted).

Another option would be blending the entire wrapper again with another layer, this time using a blend mode different from difference or exclusion. Doing so would allow us more control over the result so we're not limited to just complementaries (like black and white, or purple and green). That, however, is something we'll have to cover in a future article.

Finally, there's the option of using difference (and not exclusion) so that we get black where two identical (not necessarily white) layers overlap. For example, the difference between coral and coral is always going to be 0 on all three channels, which means black. This means we can adapt a demo like the offset and XOR frame one to get the following result:

With some properly set transparent borders and background clipping, we can also make this work for gradient backgrounds:

Similarly, we can even have an image instead of a gradient!

Note that this means we also have to invert the image background when we invert the element in the second theme scenario. But that should be no problem, because in this article we've also learned how to do that: by setting background-color to white and blending the image layer with it using background-blend-mode: exclusion!

Closing thoughts

Just these two blend modes can help us get some really cool results without resorting to canvas, SVG or duplicated layers. But we've barely scratched the surface here. In future articles, we'll dive into how other blend modes work and what we can achieve with them alone or in combination with previous ones or with other CSS visual effects such as filters. And trust me, the more tricks you have up your sleeve, the cooler the results you're able to achieve get!

以上是驯服混合模式:'差异和`excrusion'的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板