现代 CSS

Web技巧(05)

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

这是Web技巧系列的第五期,在这一期中围绕着CSS的混合模式、滤镜、渐变、暗黑模式和可动的CSS网格展开。介绍了混合模式的计算原理;如何通过滤镜实现一些特殊效果,比如Gooey效果;如何使用CSS来实现macOS的暗色模式和亮式模式之间的切换以及怎么来实现一个可动的网格,并且借助其实现一些常见的交互效果,比如off-screen。最后希望这篇文章对大家有所帮助。

混合模式和滤镜

CSS混合模式滤镜相关的特性已经不算什么新特性了,虽然还没有得到完全的应用,但在很多Web应用中已经可以看到相关的身影了,比如新版的CSS-Tricks网站就有混合模式的运用。今天第一个话题就是有关于CSS混合模式和滤镜相关的。

为什么要说CSS混合模式呢?那是前段时间看到@wgao19分享的《THIS WORLD MIXED & BLENDED》话题,让我再次感受到,CSS混合模式是如此的有意思,而且其中还暗藏深奥的相关原理。

  • 合成:形状的合成是基于每个像素的alphas进行合成
  • 混合:颜色如何在形状重叠的区域混合

说实话,以前从未关注过如何合层,事实上呢?在W3C规范中有提供过相关的原理。这一切的一切都要感谢@Thomas Porter和@Tom Duff。在该规范的第9节和第10节详细介绍:

十三种合成的功能

上图展示的是图开的合成。而混合是合成的另一个方面,主要计算 源元素和背景重叠处颜色的混合模式

从概念上讲,源元素中的颜色与背景混合在一起。混合后,将修改后的源元素与背景合成。

混合计算是有相应的公式存在的

Cm = B(Cb, Cs)
  • Cm:混合后的结果颜色
  • B:调合的配方
  • Cb:背景色(backdrop)
  • Cs:源颜色

混合公式的结果会运用到颜色范围的最小值最大值。混合函数的结果由背景的alpha调制。一个完全不透明的背景允许用混合模式来实现。一个透明的背景会导致最终的结果是源颜色和混合颜色之间的加权平均,权重由背景的alpha来控制。新颜色的值变成:

Cr = (1 - αb) x Cs + αb x B(Cb, Cs)

有关于CSS合成和混合的相关计算更多的介绍可以阅读:

上面的内容可以帮助我们很好的理解CSS的混成和混合模式的底层原理。

除了CSS的混合模式之外,还有滤镜特性:

上图展示了滤镜中不同属性产生的相应效果。但CSS滤镜的使用还是有很多小技巧和相关细节。@ChokCoco在他的《你所不知道的 CSS 滤镜技巧与细节》一文中就介绍过相关的细节。比如说:

  • filter: contrast() 或者 filter: brightness() 可以在 hover 图片的时候,调整图片的对比图或者亮度,达到聚焦用户视野的目的
  • filter:drop-shadow可以更好的处理阴影效果,有关于CSS阴影更多的细节可以阅读该文box-shadowfilter:drop-shadow
  • 滤镜动画需要大量的计算,不断的重绘页面,属于非常消耗性能的动画,使用时要注意使用场景。记得开启硬件加速及合理使用分层技术
  • blur() 混合 contrast() 滤镜效果,设置不同的颜色会产生不同的效果,使用时比较好的方法是多尝试不同颜色,观察取最好的效果;关于 blurcontrast 的融合算法,可以阅读《滤镜算法以及WebGL实现
  • 滤镜属性和transform属性类似,可以同时使用多个值,但也有顺序不同效果也不一样,比如使用 filter: contrast(150%) brightness(1.5)filter: brightness(1.5) contrast(150%) 处理同一张图片,得到的效果是不一样的,原因在于滤镜的色值处理算法对图片处理的先后顺序

另外,借助CSS的blur()contrast()可以很好的实现gooey效果:

比如下面这个示例:

上述效果的实现基于两点:

  • 图形是在被设置了 filter: contrast() 的画布背景上进行动画的
  • 进行动画的图形被设置了 filter: blur()( 进行动画的图形的父元素需要是被设置了 filter: contrast() 的画布)

意思是,上面两圆运动的背后,其实是叠加了一张设置了 filter: contrast() 的大白色背景,而两个圆形则被设置了 filter: blur(),两个条件缺一不可。

如果你对gooey效果感兴趣的话,还可以阅读:

有关于混合模式和滤镜更多的效果在Codepen上有很多,可以分别点击blend-modemix-blend-modebackground-blend-modefilter获取。

渐变中的颜色并没有那么简单

CSS渐变已经是较为成熟的一个属性了,除了常规的线性渐变(linear-gradient())、径向渐变(radial-gradient())还有较为复杂的repeating-radial-gradientrepeating-linear-gradientconic-gradient(),特别是conic-gradient()更为神奇。对于了解CSS的同学而言,CSS中渐变相关特性可以帮助我们很好的绘制一些特殊的图形和纹理。如果要想用渐变更轻易的制作出自己需要的东西(或者说还原设计稿),很有必要掌握其特性的相关细节。

有关于CSS渐变相关的介绍有:

特别是《你真的理解CSS的linear-gradient》一文让我为更好的了解一线性渐变中角度、位置是怎么来定义的。如此一来,更好的理解了线性渐变,也能让你更好的使用线性渐变。虽然该文已经很好的帮助我们理解CSS中的线性渐变,但对于渐变中的颜色,介绍的并不多。

不过值得庆幸的是,最近在meyerweb.com网站上有一篇文章详细地介绍了渐变中有关于颜色使用的相关细节

在CSS中有一个新特性,它能够在渐变中定义两个颜色停止点之间的中间点。不管是线性渐变还是径向渐变都具有相同特性,为了更好的向大家展示和说明该特性,接下来的内容将以线性渐变为例。

它们的工作方式是,你可以在渐变上定义一个点,在这个点上,颜色位于两个颜色停止点的中间位置。以#00f(蓝色)和#fff(白色)的组合为例,其中间的颜色将会是#8080ff(淡蓝色)。默认情况下,它会落在两个颜色停止点之间。比如我们的在线性渐变是这样使用linear-gradient(90deg, #00f 0, #fff 200px),那么将在100px处得到的颜色将会是#8080ff。如果你使用一个更通用的设置,比如linear-gradient(90deg, blue, white 100%),那么将在50%(容器的50%位置)的颜色会是#8080ff

上面的示例是没有显式设置中间点的一个效果。如果你在渐变是显式的设置了一个中间点,那么#8080ff的位置也就被设置好了,其余的渐变将被修改,将会创建一个更为平滑的渐变效果。比如,linear-gradient(blue 0px, 150px, white 200px),此时中间颜色#8080ff将会在150px处。从0150px#00f#8080ff的渐变,从150px200px则是#8080ff#fff的一个渐变。比如在下面这个示例:

linear-gradient(90deg, blue, 80%, white 100%)

就上面的示例而言,#8080ff被设置在80%的位置。如果容器的宽度是200px,那么#8080ff对应的位置就是在160px处;如果容器的宽度是40em,那么#8080ff就在32em处。

上面的示例中提到的容器宽度也相当于background-size属性在x轴的值。

你可能认为这本质上是两个相邻的线性渐变,这是一个可以理解的假设。首先,这是过去的情况。另一方面,如果不设置中间点,就会得到线性的过渡。比如下面这个示例,只是在鼠标悬浮时修改渐变的的角度值,即从270deg切换到90deg。容器的渐变颜色并不会有任何的变化。

background: linear-gradient(<angle>, blue, white, blue);

出现这种情况是,缓动中点位于两个停止颜色的中间位置,如果你不显式设置这个缓动中间点,那么其值默认就是50%。也就是说,下面两行代码的效果最终是一样的:

linear-gradient(0deg, blue, white, blue)

/*等同于*/

linear-gradient(0deg, blue, 50%, white, 50%, blue)

这是因为中间点缓动(Midpoint easing)算法是基于对数的,其目的是产生50%中间点的线性缓动。

不过,在一般情况下,它是一个对数算法。如果中点不在颜色停止点的正中间,则会出现非线性缓动(non-linear easing)。更重要的是,将出现非线性,非对称的缓动(easing)。比如下面这个示例:

linear-gradient(<angle>, blue, 10%, white, 90%, blue)

如果角度在90deg270deg切换时的效果:

该文章中还提到一个更有意思的东西,在渐变中我们可以像transitionanimation一样,使用transition-timing-function这样的缓动函数。比如:linear-gradient(90deg, blue, 66.6%, white)效果非常接近linear-gradient(90deg, blue, ease-in, white)。在20-30%的区域有分歧,但这是相当小的分歧。设置一个临时的颜色停止可能会使它更整齐。比如linear-gradient(90deg, blue, ease-out, white)接近于linear-gradient(90deg, blue, 23%, #afafff 50%, 68%, white, 93%)

上面的示例都是单向的,而不是对称的。比如下面这个示例,探索了一些非对称的渐变。

linear-gradient(90deg, blue, ease-in, white, ease-out, blue)

linear-gradient(90deg, blue, 33.3%, white 50%, 61.5%, #5050FF 75%, 84%, blue 93%)

在渐变中看到ease-in-outease-out身影,这是非常神奇的事情。或许在不久的将来,我们就可以在渐变中使用了,让渐变效果更为细滑。

CSS的暗色模式

在macOS系统中提供了一个高亮和暗色系的主题切换:

Safari技术预浏版本68发布了一个名为prefers-color-scheme的新特性,该特性允许我们检测用户是否通过媒体查询启用了暗模式。

@media (prefers-color-scheme: dark) {

}

prefers-color-scheme接受darklight两种模式。

早前 @Marcin Wichary 采用自定义属性模拟出类似的一个场景

html {
    --text-color-normal: #0a244d;
    --text-color-light: #8cabd9;
}

html[data-theme='dark'] {
    --text-color-normal: hsl(210, 10%, 62%);
    --text-color-light: hsl(210, 15%, 35%);
    --text-color-richer: hsl(210, 50%, 72%);
    --text-color-highlight: hsl(25, 70%, 45%);
}

正如 @Jonas Duri 的《Use “prefers-color-scheme” to detect macOS dark mode with CSS and Javascript》文章中提到的一样,我们可以将两者结合起来使用:

:root {
    --background-color: #fff;
    --page-width: 70em;
    --primary-color: #151513;
    --font-color: #151513;
    --subtle-primary-color: #151513;
    --block-background-color: #f1f3f4;
    --menu-item-color: #000;
    --menu-item-hover-color: #000;
    --menu-item-alert-bg: #ffffff;
    --menu-item-alert-shadow: #dfe1e7;
    --alert-border-color: #dfe1e7;
    --tertiary-color:: #727680;
}

@media (prefers-color-scheme: light) {
    :root {
        --background-color: #fff;
        --page-width: 70em;
        --primary-color: #151513;
        --font-color: #151513;
        --subtle-primary-color: #151513;
        --block-background-color: #f1f3f4;
        --menu-item-color: #000;
        --menu-item-hover-color: #000;
        --menu-item-alert-bg: #ffffff;
        --menu-item-alert-shadow: #dfe1e7;
        --alert-border-color: #dfe1e7;
        --tertiary-color:: #727680;
    }
}

@media (prefers-color-scheme: dark) {
    :root {
        --background-color: #1e1e1e;
        --primary-color: #157efb;
        --font-color: #dedede;
        --subtle-primary-color: #151513;
        --block-background-color: #323232;
        --menu-item-color: #dedede;
        --menu-item-hover-color: #157efb;
        --menu-item-alert-bg: #151513;
        --menu-item-alert-shadow: #151513;
        --alert-border-color: #000;
        --tertiary-color:: #727680;
    }
}

在未来的Safari中,将会提供color-scheme属性:

:root {
    color-scheme: light dark;
}

:root上指定了lightdark两个值,让引擎知道文档支持这两种模式。这将更改页面的默认文本和背景颜色,以匹配当前系统外观。此外,标准表单控件、滚动条和其他命名的系统颜色会自动更改它们的外观。如果没有这个声明,引擎使用深色表单控件或深色配色方案将是不安全的,因为许多文档都是使用假定的浅色配色方案设计的。

例如,在页面中指定了color-scheme: light dark,将完全可以在两种外观中切换:

结合prefers-color-scheme我们可以这样来使用:

:root {
    color-scheme: light dark;
    --special-text-color: hsla(60, 100%, 50%, 0.5);
    --border-color: black;
}

@media (prefers-color-scheme: dark) {
    :root {
        --special-text-color: hsla(60, 50%, 70%, 0.75);
        --border-color: white;
    }
}

.special {
    color: var(--special-text-color);
    border: 1px solid var(--border-color);
}

是不是非常有意思。如果你想了解更多这方面的信息可以阅读:

虽然上面的方法可以很好的实现暗色和亮色系的切换。但这目前也仅仅是在macOS系统中。但如果真的想在项目中要实现类似的效果呢?

文章最开头提到了CSS的混合模式。事实上,我们可以借助CSS混合模式来帮助我们达到类似的效果。@wgao19在最新的博文中就介绍了这样的方法:

很简单,只需要采用mix-blend-mode: difference即可。比如:

.dark-mode-screen {
    width: 100vw;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    background: white;
    mix-blend-mode: difference;
}

如果你想让页面中部分元素不忽略mix-blend-mode:difference带来的影响,可以使用isolation: isolate

.twitter-logo,
.emoji {
    isolation: isolate; 
}

上面的示例是我们将页面之间的差异与白色进行对比,类似于补色一样。如果你将白色修改成别的颜色,你将会得到与众不同的效果。比如:

可以动的CSS Grid

CSS Grid是什么,这里不说了。从未了解的同学,可以点击这里进行了解

但可以动的CSS Grid是什么呢?简单地说,借助于@keyframes在不同的帧中来修改grid-template-rowsgrid-template-columns的值,让你的网格布局动起来。

.element{
    grid-template-columns: 1fr 1fr 1fr;
    animation: resize 2000ms ease infinite alternate;
}

@keyframes resize {
    to {
        grid-template-columns: 1fr 2fr 1fr;
    }
}

比如 @Michelle Barker写的一个示例:

同样的原理,我们可以修改grid-gap的值,实现类似于off-screen的效果:

.grid{
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: 300px;
    animation: gap 2s;
}

@keyframes gap{
    from{
        grid-gap: 100%;
    }
    to{
        grid-gap: 0%;
    }
}

比如@Manuel Matuzovic写的Demo:

有关于这方面更详细的介绍,可以阅读@Facundo Corradini的《New in Firefox 66: animating CSS Grid》一文。

小结

今天主要围绕着CSS的混合模式、滤镜、渐变、暗黑模式和可动的CSS网格展开。希望大家对这些东西能感兴趣,更希望对大家有所帮助。如果你有更好的技巧或经验,欢迎在下面的评论中与我们一起共享。nike air max 90 china

返回顶部