整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

网页颜色一键变灰?分享 1 段优质 CSS 代码片段!

内容首发于工粽号:程序员大澈,每日分享一段优质代码片段,欢迎关注和投稿!

大家好,我是大澈!

本文约 1100+ 字,整篇阅读约需 2 分钟。

今天分享一段优质 CSS 代码片段,应用灰度效果,让页面变成黑白显示。

老规矩,先阅读代码片段并思考,再看代码解析再思考,最后评论区留下你的见解!


body {
  filter: grayscale(1); // 1相当于100%
}


分享原因

这段代码展示了如何使用 CSS 滤镜来将整个网页变为灰度效果。

在特殊的日子里,网页有整体变灰色的需求,可以使用这段代码,这个需求很有必要。

再就是做一些老照片或黑白电影的效果,也可以使用这段代码。

代码解析

1. 选择器 body

这一部分选择了 HTML 文档的 <body> 元素,即整个网页的主体。

CSS 的 filter 属性通常用于图像,但也可以应用到其他任何 HTML 元素上。

2. grayscale(1);

grayscale 滤镜将元素的颜色变成灰度效果。

参数 1 表示 100% 灰度,参数 0 表示无灰度效果。

3. filter 所有属性值 大盘点!

CSS 的 filter 属性提供了多种图形效果,且这些属性值可以组合用起来,且可以应用于任何元素。

以下是 filter 属性的所有值及其详细解释:

blur()

功能:应用模糊效果。

参数:接受一个长度值(如 px、em),默认值是 0。

示例:filter: blur(5px);

brightness()

功能:调整图像的亮度。

参数:接受一个数值,1 为原始亮度。值小于 1 会降低亮度,值大于 1 会增加亮度。

示例:filter: brightness(0.5);

contrast()

功能:调整图像的对比度。

参数:接受一个数值,1 为原始对比度。值小于 1 会降低对比度,值大于 1 会增加对比度。

示例:filter: contrast(200%);

drop-shadow()

功能:应用阴影效果。

参数:类似于 box-shadow,包括偏移量、模糊半径和颜色。

示例:filter: drop-shadow(10px 10px 10px #000);

grayscale()

功能:将图像变为灰度。

参数:接受一个 0 到 1 之间的数值,0 为无灰度,1 为完全灰度。

示例:filter: grayscale(1);

hue-rotate()

功能:旋转图像的色相。

参数:接受一个角度值,单位为度(deg)。

示例:filter: hue-rotate(90deg);

invert()

功能:反转图像的颜色。

参数:接受一个 0 到 1 之间的数值,0 为无效果,1 为完全反转。

示例:filter: invert(1);

opacity()

功能:调整图像的透明度。

参数:接受一个 0 到 1 之间的数值,0 为完全透明,1 为完全不透明。

示例:filter: opacity(0.5);

saturate()

功能:调整图像的饱和度。

参数:接受一个数值,1 为原始饱和度。值小于 1 会降低饱和度,值大于 1 会增加饱和度。

示例:filter: saturate(2);

sepia()

功能:将图像变为棕褐色。

参数:接受一个 0 到 1 之间的数值,0 为无效果,1 为完全棕褐色。

示例:filter: sepia(1);

url()

功能:引用 SVG 滤镜。

参数:接受一个 URL,指向一个包含 SVG 滤镜的文件。

示例:filter: url(#filter-id);


- end -

篇文章面向那些已经熟练使用for循环,但对Array.map和Array.filter并没有特别理解的开发者。本文将会手把手去实现这两个函数,来深入理解它们的工作原理。

Array.map

Array.map通过对输入的数组中每一个元素进行变换,返回由变换后的元素按序组成的新数组。原始数组的值不会被修改。假设我们相对一个数组中的每一个元素乘以3,使用for循环可以这样写。

for循环

var originalArr = [1, 2, 3, 4, 5];
var newArr = [];
for(var i = 0; i < originalArr.length; i++) {
 newArr[i] = originalArr[i] * 3;
}
console.log(newArr); // -> [3, 6, 9, 12, 15]

接下来我们将这个for循环抽象成一个函数。

multiplyByThree函数

var originalArr = [1, 2, 3, 4, 5];
function multiplyByThree(arr) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = arr[i] * 3;
 }
 return newArr;
}
var arrTransformed = multiplyByThree(originalArr);
console.log(arrTransformed); // -> [3, 6, 9, 12, 15]

现在我们继续深化这个抽象思路,将multiplyByThree中对每一个元素乘以3部分抽象为一个新的函数。

var originalArr = [1, 2, 3, 4, 5];
function timesThree(item) {
 return item * 3;
}
function multiplyByThree(arr) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = timesThree(arr[i]);
 }
 return newArr;
}
var arrTransformed = multiplyByThree(originalArr);
console.log(arrTransformed); // -> [3, 6, 9, 12, 15]

这样有什么好处呢?设想如果我们想对每一个元素乘以5,或则10,我们还要把整个for循环写一遍吗!

如果我们对timesThree函数稍作修改,就可以轻松的复用很多代码。

multiply函数

我们将:

function multiplyByThree(arr) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = timesThree(arr[i]);
 }
 return newArr;
}

重构为:

function multiply(arr, multiplyFunction) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = multiplyFunction(arr[i]);
 }
 return newArr;
}

我们将multiplyByThree重命名为multiply,并增加了一个参数。该参数是一个函数,定义了数组元素的变换规则。通过定义一个timesThree函数来达到实现对每一个数组元素乘以3的目的。

var originalArr = [1, 2, 3, 4, 5];
function timesThree(item) {
 return item * 3;
}
var arrTimesThree = multiply(originalArr, timesThree);
console.log(arrTimesThree); // -> [3, 6, 9, 12, 15]

有何优点呢?我们可以很简单定义任何变换:

var originalArr = [1, 2, 3, 4, 5];
function timesFive(item) {
 return item * 5;
}
var arrTimesFive = multiply(originalArr, timesFive);
console.log(arrTimesFive); // -> [5, 10, 15, 20, 25]

Map

我们进一步抽象:

function multiply(arr, multiplyFunction) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = multiplyFunction(arr[i]);
 }
 return newArr;
}

将multiply改为map, multiplyFunction改为transform:

function map(arr, transform) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = transform(arr[i]);
 }
 return newArr;
}

我们可以将任何对单个元素操作的函数传入map函数。比如,我们将所有字符都变换成大写:

function makeUpperCase(str) {
 return str.toUpperCase();
}
var arr = ['abc', 'def', 'ghi'];
var ARR = map(arr, makeUpperCase);
console.log(ARR); // -> ['ABC', 'DEF, 'GHI']

Array.map

我们定义的map函数和原生的Array.map还是有区别的:数组不再需要作为第一个参数传入,而是在点(.)的左侧。如果使用我们定义的map函数,如下:

function func(item) {
 return item * 3;
}
var arr = [1, 2, 3];
var newArr = map(arr, func);
console.log(newArr); // -> [3, 6, 9]

将其改写为使用Array.map函数的形式:

function func(item) {
 return item * 3;
}
var arr = [1, 2, 3];
var newArr = arr.map(func);
console.log(newArr); // -> [3, 6, 9]

Arrary.map参数解析

除了变换函数外,Array.map还可以接收其它两个参数: 数组索引(index), 原始的数组。

function logItem(item) {
 console.log(item);
}
function logAll(item, index, arr) {
 console.log(item, index, arr);
}
var arr = ['abc', 'def', 'ghi'];
arr.map(logItem); // -> 'abc', 'def', 'ghi'
arr.map(logAll); // -> 'abc', 0, ['abc', 'def', 'ghi']
 // -> 'def', 1, ['abc', 'def', 'ghi']
 // -> 'ghi', 2, ['abc', 'def', 'ghi']

因此,你可以再变换函数中使用索引和原始的数组。比如:你想要将一个列表变为带序号的列表,则需要使用索引(index)参数:

function multiplyByIndex(item, index) {
 return (index + 1) + '. ' + item;
}
var arr = ['bananas', 'tomatoes', 'pasta', 'protein shakes'];
var mappedArr = arr.map(multiplyByIndex);
console.log(mappedArr); // ->
// ["1. bananas", "2. tomatoes", "3. pasta", "4. protein shakes"]

因此,我们自己实现的map函数也应该支持这两个参数:

function map(arr, transform) {
 var newArr = [];
 
 for(var i = 0; i < arr.length; i++) {
 newArr[i] = transform(arr[i], i, arr);
 }
 return newArr;
}

当然,Array.map函数还有一些错误检查和执行优化的代码,我们定义的map只编码了核心功能。

Array.filter

Array.filter将数组中不满足条件的元素过滤,我们可以用for循环加上Array.push来实现。

for-loop

下面这段JS代码将所有大于5的元素筛选出来:

var arr = [2, 4, 6, 8, 10];
var filteredArr = [];
for(var i = 0; i < arr.length; i++) {
 if(arr[i] > 5) {
 filteredArr.push(arr[i]);
 }
}
console.log(filteredArr); // -> [6, 8, 10]

我们可以抽象这段代码,定义为一个函数:

function filterLessThanFive(arr) {
 var filteredArr = [];
 for(var i = 0; i < arr.length; i++) {
 if(arr[i] > 5){
 filteredArr.push(arr[i]);
 }
 }
 return filteredArr;
}
var arr1 = [2, 4, 6, 8, 10];
var arr1Filtered = filterLessThanFive(arr1);
console.log(arr1Filtered); // -> [6, 8, 10]

进一步抽象,将过滤条件抽出来:

function isGreaterThan5(item) {
 return item > 5;
}
function filterLessThanFive(arr) {
 var filteredArr = [];
 for(var i = 0; i < arr.length; i++) {
 if(isGreaterThan5(arr[i])) {
 filteredArr.push(arr[i]);
 }
 }
 return filteredArr;
}
var originalArr = [2, 4, 6, 8, 10];
var newArr = filterLessThanFive(originalArr);
console.log(newArr); // -> [6, 8, 10]

将过滤条件函数作为参数传入:

function filterBelow(arr, greaterThan) {
 var filteredArr = [];
 for(var i = 0; i < arr.length; i++) {
 if(greaterThan(arr[i])) {
 filteredArr.push(arr[i]);
 }
 }
 return filteredArr;
}
var originalArr = [2, 4, 6, 8, 10];

大功告成!我们可以使用如下代码来取出所有大于5的元素:

function isGreaterThan5(item) {
 return item > 5;
}
var newArr = filterBelow(originalArr, isGreaterThan5);
console.log(newArr); // -> [6, 8, 10];

Array.filter

我们将filterBelow重命名为filter, greaterThan重命名为testFunction:

function filter(arr, testFunction) {
 var filteredArr = [];
 for(var i = 0; i < arr.length; i++) {
 if(testFunction(arr[i])) {
 filteredArr.push(arr[i]);
 }
 }
 return filteredArr;
}

这就是一个基本的Array.filter函数了!

var arr = ['abc', 'def', 'ghijkl', 'mnopuv'];
function longerThanThree(str) {
 return str.length > 3;
}
var newArr1 = filter(arr, longerThanThree);
var newArr2 = arr.filter(longerThanThree);
console.log(newArr1); // -> ['ghijkl', 'mnopuv']
console.log(newArr2); // -> ['ghijkl', 'mnopuv']

同样,Array.filter也有索引(index)和原始数组这两个额外参数。

function func(item, index, arr) {
 console.log(item, index, arr);
}
var arr = ['abc', 'def', 'ghi'];
arr.filter(func); // -> 'abc', 0, ['abc', 'def', 'ghi']
 // -> 'def', 1, ['abc', 'def', 'ghi']
 // -> 'ghi', 2, ['abc', 'def', 'ghi']

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用

以上就是小编的分享,感谢各位大佬们耐心的看完文章,最后再分享一个我自己的后端技术群,群里自己收集了很多Java架构资料,大家可以进群免费领取资料,群号:680075317,也可以进群一起交流,比如遇到技术瓶颈、面试不过的,大家一些交流学习!

23 年的 CSS 新特性中,有一个非常重要的功能更新 -- 相对颜色

简单而言,相对颜色的功能,让我们在 CSS 中,对颜色有了更为强大的掌控能力。

其核心功能就是,让我们能够基于一个现有颜色 A,通过一定的转换规则,快速生成我们想要的颜色 B

其功能能够涵盖:

  • 精简
  • 调暗
  • 饱和度
  • 降低饱和度
  • 色度增强
  • 调整不透明度
  • 反转
  • 补充
  • 转换
  • 对比度
  • 调色板

当然,今天我们不会一个一个去过这些功能,更多的时候,我们只需要知道我们能够实现这些功能。

本文,我们将从实际实用角度出发,基于实际的案例,看看 CSS 相对颜色,能够如何解决我们的一些实际问题。

快速语法入门

首先,我们通过一张图,一个案例,快速入门 CSS 相对颜色语法:

相对颜色语法的目标是允许从另一种颜色派生颜色。

上图显示了将原始颜色 green 转换为新颜色的颜色空间后,该颜色会转换为以 r、g、b 和 alpha 变量表示的各个数字,这些数字随后会直接用作新的 rgb() 颜色的值。

举个例子:

<p> CSS Relative Color </p>
p {
    color: rgb(255, 0, 0);
}

实现一个 color 为红色(rgb 值为 rgb(255, 0, 0))的字体:

基于上面的相对颜色语法,我如何通过一个红色生成绿色文字呢?示意如下:

p {
    --color: rgb(255, 0, 0);
    color: rgb(from var(--color) calc(r - 255) calc(g + 255) b);  /* result = rgb(0, 255, 0) */
}

效果如下,我们就得到绿色字体:

解释一下:

  1. 原本的红色颜色,我们把它设置为 CSS 变量 --color: rgb(255, 0, 0)
  2. 想通过红色得到绿色,对于红色的 rgb 值 rgb(255, 0, 0) 而言,需要转换成 rgb(0, 255, 0)
  3. 使用 CSS 相对颜色语法,就是 rgb(from var(--color) calc(r - 255) calc(g + 255) b)

通过这个 DEMO,我们把几个核心基础语法点学习一下:

  1. from 关键字

from 关键字,它是相对颜色的核心。它表示会将 from 关键字后的颜色定义转换为相对颜色!在 from 关键字后面,CSS 会期待一种颜色,即能够启发生成另一种颜色

  1. from 关键字 后的颜色表示,支持不同颜色表示或者是 CSS 变量

第二个关键点,from 后面通常会接一个颜色值,这个颜色值可以是任意颜色表示法,或者是一个 CSS 变量,下面的写法都是合法的:

p {
    color: rgba(from #ff0000) r g b);
    color: rgb(from rgb(255, 0, 0) r g b);
    color: rgb(from hsl(0deg, 100%, 50%) r g b);
    color: rgb(from var(--hotpink) r g b);
}
  1. 对转换后的变量使用 calc() 或其他 CSS 函数

另外一个非常重要的基础概念就是,我们可以对 (from color r g b) 后的转换变量 r g b 使用 calc() 或其他 CSS 函数。

就是我们上面的例子:

p {
    --color: rgb(255, 0, 0);
    color: rgb(from var(--color) calc(r - 255) calc(g + 255) b);  /* result = rgb(0, 255, 0) */
}
  1. 相对颜色语法支持,各种颜色表示函数:

相对颜色的基础的使用规则就是这样,它不仅支持 rgb 颜色表示法,它支持所有的颜色表示法:

  • sRGB 颜色空间:hsl()、hwb()、rgb();
  • CIELAB 颜色空间:lab()、lch();
  • Oklab 颜色空间:oklab()、oklch();

使用 CSS 相对颜色,实现统一按钮点击背景切换

通常页面上的按钮,都会有 hover/active 的颜色变化,以增强与用户的交互。

像是这样:

最常见的写法,就是我们需要在 Normal 状态、Hover 状态、Active 状态下写 3 种颜色:

p {
    color: #ffcc00;
    transition: .3s all;
}
/* Hover 伪类下为 B 颜色 */
p:hover {
    color: #ffd21f;
}
/** Active 伪类下为 C 颜色 **/
p:active {
    color: #ab8a05;
}

在之前,我们介绍过一种利用滤镜 filter: contrast() 或者 filter: brightness() 的统一解决方案,无需写多个颜色值,可以根据 Normal 状态下的色值,通过滤镜统一实现更亮、或者更暗的伪类颜色。

在今天,我们也可以利用 CSS 相对颜色来做这个事情:

div {
    --bg: #fc0;
    background: var(--bg);
    transition: .3s all;
}

div:hover {
    background: hsl(from var(--bg) h s calc(l * 1.2));
}
div:active {
    background: hsl(from var(--bg) h s calc(l * 0.8));
}

我们通过 hsl 色相、饱和度、亮度颜色表示法表示颜色。实现:

  1. 在 :hover 状态下,根据背景色,将背景亮度 l 调整为原背景色的 1.2 倍
  2. 在 :avtive 状态下,根据背景色,将背景亮度 l 调整为原背景色的 0.8 倍

在实际业务中,这是一个非常有用的用法。

使用 CSS 相对颜色,实现文字颜色自适应背景

相对颜色,还有一个非常有意思的场景 -- 让文字颜色能够自适应背景颜色进行展示。

有这么一种场景,有的时候,无法确定文案的背景颜色的最终表现值(因为背景颜色的值可能是后台配置,通过接口传给前端),但是,我们又需要能够让文字在任何背景颜色下都正常展现(譬如当底色为黑色时文字应该是白色,当背景为白色时,文字应该为黑色)。

像是这样:

在不确定背景颜色的情况下,无论什么情况,文字颜色都能够适配背景的颜色。

在之前,纯 CSS 没有特别好的方案,可以利用 mix-blend-mode: difference 进行一定程度的适配:

div {
    // 不确定的背景色
}
p {
    color: #fff;
    mix-blend-mode: difference;
}

实操过这个方案的同学都会知道,在一定情况下,前景文字颜色还是会有一点瑕疵。并且,混合模式这个方案最大的问题是会影响清晰度

有了 CSS 相对颜色后,我们有了更多的纯 CSS 方案。

利用 CSS 相对颜色,反转颜色

我们可以利用相对颜色的能力,基于背景色颜色进行反转,赋值给 color。

一种方法是将颜色转换为 RGB,然后从 1 中减去每个通道的值。

代码非常简单:

p {
    /** 任意背景色 **/
    --bg: #ffcc00;
    background: var(--bg);

    color: rgb(from var(--bg) calc(1 - r) calc(1 - g) calc(1 - b));  /** 基于背景反转颜色 **/
}

用 1 去减,而不是用 255 去,是因为此刻,会将 rgb() 表示法中的 0~255 映射到 0~1。

效果如下:

配个动图,我们利用背景色的反色当 Color 颜色,适配所有背景情况:

完整的 DEMO 和代码,你可以戳这里:CodePen Demo -- CSS Relatvie Color Adapt BG

当然,这个方案还有两个问题:

  1. 如果颜色恰好是在 #808080 灰色附近,它的反色,其实还是它自己!会导致在灰色背景下,前景文字不可见;
  2. 绝大部分情况虽然可以正常展示,但是并不是非常美观好看

为了解决这两个问题,CSS 颜色规范在 CSS Color Module Level 6 又推出了一个新的规范 -- color-contrast()

利用 color-contrast(),选择高对比度颜色

color-contrast() 函数标记接收一个 color 值,并将其与其他的 color 值比较,从列表中选择最高对比度的颜色。

利用这个 CSS 颜色函数,可以完美的解决上述的问题。

我们只需要提供 #fff 白色和 #000 黑色两种可选颜色,将这两种颜色和提供的背景色进行比较,系统会自动选取对比度更高的颜色。

改造一下,上面的代码,它就变成了:

p {
    /** 任意背景色 **/
    --bg: #ffcc00;
    background: var(--bg);

    color: color-contrast(var(--bg) vs #fff, #000);  /** 基于背景色,自动选择对比度更高的颜色 **/
}

这样,上面的 DEMO 最终效果就变成了:

此方案的优势在于:

  1. 可以限定前景 color 颜色为固定的几个色值,以保证 UI 层面的统一及美观
  2. 满足任何情况下的背景色

当然,唯一限制这个方案的最大问题在于,当前,color-contrast 还只是一个实验室功能,未大规模被兼容。

总结一下

到今天,我们可以利用 CSS 提供的各类颜色函数,对颜色有了更为强大的掌控力。

很多交互效果,不借助 JavaScript 的运算,也能计算出我们想要的最终颜色值。本文简单的借助:

  1. 使用 CSS 相对颜色,实现统一按钮点击背景切换
  2. 使用 CSS 相对颜色,实现文字颜色自适应背景

两个案例,介绍了 CSS 相对颜色的功能。


原文链接:https://juejin.cn/post/7321410822789742618