Quantcast
Channel: w3cplus
Viewing all articles
Browse latest Browse all 1557

CSS秘密花园:色调

$
0
0

CSS Secrets》是@Lea Verou最新著作,这本书讲解了有关于CSS中一些小秘密。是一本CSSer值得一读的一本书,经过一段时间的阅读,我、@南北@彦子一起将在W3cplus发布一系列相关的读后感,与大家一起分享。

CSS Secrets

问题

为灰度图像添加色调(或已经转换为灰度的图像)是让一组风格非常不同的图像得到视觉上的和谐的一种流行而且优雅的方式。通常情况下,这样的效果是通过:hover或其它的交互来静态地添加和删除的。

过去,我们使用一个图像编辑程序来创建两个版本的图像,然后写一些简单的CSS代码来完成它们之间的切换。这种方法是可行的,但是它添加了额外的HTTP请求,而且维护非常麻烦。想象一下如果要改变颜色效果:你需要准备好所有的图像,还要创建新的黑白版本!

色调

2014年CSSConf网站使用了这种效果来展示用户的照片,只有在hoverfocus的时候展示全彩色的原照片。

其它方法也基本是覆盖一个半透明颜色在图像正上方,或为图像应用透明度值并使用纯色覆盖。但是,这并不是真正的调色:不仅没有把图像上的所有颜色转换成目标颜色,还大大地降低了对比度。

还有一些脚本可以把图像转变成一个<canvas>元素,然后通过JavaScript应用调色。这确实会产生适当的调色,但是是相当缓慢而且有限制的。

如果能够将色调直接从我们的CSS应用到图像不是更方便吗?

基于滤镜的解决方案

因为没有专门为这个效果设计的滤镜功能,我们需要运用一点技巧,结合多个滤镜来完成。

我们应用的第一个滤镜是sepia(),它能够给图像一个饱和的橙黄色调,大多数像素的色相约为35-40。如果这是我们想要的颜色,那我们到这里就大功告成了。

色调

然而在大多数情况下,这并不是。如果我们的颜色更饱和,我们可以使用saturate()滤镜来提高每个像素的饱和度。假设我们想要给图像一个hsl(335, 100%, 50%)的调色,我们需要增加相当多的饱和度,所以我们使用参数为4。根据具体情况选择确切的值。如下图所示,这种组合滤镜给我们的图像有了一个温暖的金色色调。

色调

上图是原始图,下图是使用了sepia()滤镜的效果

我们的图像现在看起来不错,如果我们不想要用这种橙黄色色调了,想换成一个更深更明亮的粉红色。这时,我们就需要应用一个hue-rotate()滤镜,根据我们指定的度数来调整每个像素的色相。让色相从335减少40左右,我们需要添加参数295(335 - 40):

filter: sepia() saturate(4) hue-rotate(295deg);

在这个时候,我们已经为我们的图像调色,你可以在下图中看到效果。

色调

如果这是在:hover或其它状态触发的效果,我们可以为它应用CSS过渡:

img {
    transition: .5s filter;
    filter: sepia() saturate(4) hue-rotate(295deg);
}
img:hover,
img:focus {
    filter: none;
}

混合模式解决方案

滤镜解决方案是可行的,但是你可能注意到了结果和通过图像编辑器获得的并不完全相同。即使我们想要用一个非常明亮的颜色着色,结果看起来仍然像被水洗了一样。如果我们试图去增加saturate()滤镜的参数的值,我们会得到一个不同的更过于风格化的效果。值得庆幸的是,我们有一个更好的解决方案:混合模式!

如果你曾经使用过想Adobe Photoshop这样的图像编辑器,你可能已经对混合模式非常熟悉了。当两个元素重叠,混合模式控制最顶端元素的颜色如何和它下方的元素的颜色混合。当涉及到图像着色,你需要的混色模式是luminosity(亮度模式)。luminosity混合模式保留最上面元素的HSL亮度,应用背景元素的色相和饱和度。如果背景是我们想要应用的颜色,而应用了混合模式的元素正好是我们的图像,这不就是调色的本质?

色调

对比一下filter和混合模式两种方法的效果,上图是filter效果,下图是混合模式效果

要为元素应用混合模式,有两个可用的属性:mix-blend-mode用于为整个元素应用混合模式,background-blend-mode用于单独为每个背景图层应用混合模式。这意味着要在一个图像上使用这种方法,我们有两个选择,但是他们都不理想:

  • 把我们的图像和我们想要的颜色的背景颜色放在同一个容器中
  • 使用<div>,而不是图像,这样可以把background-image设置为我们想要上色的图像,和放在我们的颜色下方的第二个背景图层

根据具体的使用情况,我们在两者中选取一种方法。比如说,如果我们想要为一个<img>元素应用效果,我们需要把它包裹在另一个元素中。但是,需要我们已经有另一个元素了,如一个<a>,我们可以这样使用:

<a href="#something">
    <img src="tiger.jpg" alt="Rawrrr!" />
</a>

这样,你只需要两个声明来应用这个效果:

a {
    background: hsl(335, 100%, 50%);
}
img {
    mix-blend-mode: luminosity;
}

和CSS滤镜一样,混合模式也可以优雅地降级:如果它们不被支持,没有效果会被应用,图像依旧完全可见。

有一个需要考虑的是,滤镜可以有动画效果,但混合模式没有。我们已经看到过这样的效果,filter属性下的一个简单的CSS过滤,可以让图片慢慢淡化为单色,但是在混合模式下没办法产生这样的效果。但是,不必担心,这不是动画出了什么问题,这只是意味着我们需要跳出固有思维。

如前面已经解释的,mix-blend-mode是混合元素下面的所有内容。因此,如果我们通过这个属性应用luminosity混合模式,图像总会有东西混合。但是,使用background-blend-mode属性会混合下面的每个背景图像层,不考虑元素之外的任何东西。所以,当我们只有一个背景图像和一个transparent背景颜色时,会发生什么呢?你猜对了:没有任何混合发生!

我们可以利用这个优势,使用background-blend-mode属性来完成效果。HTML的内容会有点不一样:

<div class="tinted-image"
    style="background-image:url(tiger.jpg)">
</div>

那么我们只需要为一个<div>应用CSS,因为这种技术不需要任何多余的元素:

.tinted-image {
    width: 640px; height: 440px;
    background-size: cover;
    background-color: hsl(335, 100%, 50%);
    background-blend-mode: luminosity;
    transition: .5s background-color;
}
.tinted-image:hover {
    background-color: transparent;
}

但是,如前面提到的,这两种技术都不理想。这里运行的主要问题是:

  • 图像的尺寸需要在CSS代码中写好硬性的widthheight
  • 语义上,这不是一个图像,所以不会被屏幕阅读器理解

就像生活中的大多数事情一样,没有完美的方法,但是在本节中,我们已经看到了三种不同的可以应用这个效果的方法,每一种方法都有其优点和缺点。你需要根据自己项目的具体需求来选择合适的方案。

如需转载,烦请注明出处:http://www.w3cplus.com/css3/css-secrets/color-tinting.html


Viewing all articles
Browse latest Browse all 1557

Trending Articles