如何在网页置灰的时候,部分元素保持彩色-有意思的面试题

一键变灰

这个大部分同学都写了,直接

html{filter: grayscale(100%);
} 

考虑ie之类的兼容性的话,就直接把兼容性的属性都搞上去

html{-webkit-filter: grayscale(100%);-moz-filter: grayscale(100%);-ms-filter: grayscale(100%);-o-filter: grayscale(100%);filter: grayscale(100%);filter: gray;filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
} 

如果想控制的更动态一些,可以用js控制html的class来实现这个切换过程

<button class="btn" id="set-gray">置灰</button> 
let style = document.createElement('style')
let graySelector = 'gray-filter'
style.setAttribute('type', 'text/css')
// style.setAttribute('data-vite-dev-id', id)
style.textContent = `.${graySelector}{-webkit-filter: grayscale(100%);-moz-filter: grayscale(100%);-ms-filter: grayscale(100%);-o-filter: grayscale(100%);filter: grayscale(100%);filter: gray;filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
}`
document.head.appendChild(style)

let root = document.querySelector('html')
let btn = document.querySelector('#set-gray')
btn && btn.addEventListener('click', () => {setAllGray()
}, false)

function toggleClassName(el,name){if (el.className.indexOf(name) > -1) {el.className = el.className.replace(name, '').trim()} else {el.className = [el.className, name].join(' ')}
}

function setAllGray() {toggleClassName(root,graySelector)
} 

这样可以在后端通过接口的形式决定是不是加载这段js就可以了

那么问题来了,如何在置灰的前提下部分元素保持彩色呢

filter重置(失败)

如果能直接某个元素重置filter, 尝试下面的写法,但是不生效

html{filter:grayscale(100%);
}
.not-gray{filter:none;
} 

如果filter的算法可逆的话,可以在.not-gray元素上设置一个翻转的filter,查了点资料,Chromium灰色100%的算法如下, 我本人图像处理方面比较菜,但是看起来全灰的算法不可逆,而且如果在元素上再盖一个canvas也不太好弄 放弃

R/G/B = 0.2126R' + 0.7152G' + 0.0722'B 

遮挡解决方案 backdrop-filter

有一个解决方案是用backdrop-filter做一个遮罩,毕竟filter还是有点损耗首屏性能的,虽然可以用transform开启硬件优化一些,我们还可以用遮罩的方式挡住也可以的,并且设置pointer-events: none;不阻挡用户交互,也是一段css搞定

html {position: relative;width: 100%;height: 100%;
}
html::before {content: "";position: fixed;backdrop-filter: grayscale(100%);pointer-events: none;inset: 0;z-index: 100;
} 

还可以把遮罩的position换成absolute, 实现一个只置灰首屏的效果,不过我感觉没啥必要

然后我们可以设置指定元素的z-index,超过backdrop-filter的100就可以, 就有首屏+部分彩色的效果

.not-gray{position: relative;z-index:1000;
} 

元素遍历标记

backdrop-filter其实也有他的兼容性问题,尤其是firefox版本102(最新107)之前都不能用,filter方案更普及一些,不过作为面试题的话 我们还可以继续用filter这个方法,

我们设置有一些选择器保持彩色,然后统计出当前这个网页中,需要置灰的元素,网页是一个属性结果,我们先对选中元素的父元素进行遍历标记

 let body = document.body
//配置选择器,命中这个列表选择器的不置灰
let selectors = ['#not-gray2', '.not-gray3']
selectors.forEach(selector=>{let doms = [...document.querySelectorAll(selector)].forEach(v=>{if(!v) return v.staycolor = truelet parent = v.parentNodewhile(parent && !parent.colorful){parent.colorful = trueparent = parent.parentNode}})
}) 

然后现在需要置灰的元素都已经标记了colorful,然后我们遍历一下,递归每个child,如果没有colorful,直接置灰返回,通过递归就可以把所有元素都置灰了

let graySelector = 'gray-filter'
walk(body)

function walk(node){if(node.nodeType!==1) return if(node.staycolor) return if(!node.colorful){toggleClassName(node,graySelector)return}for (var i = 0; i < node.children.length; i++) {var child = node.children[i]; walk(child)}} 

可以把selectors做成从后端读取,就可以动态设置保持彩色的部分了, 不过这样设置filter可能会导致部分元素的定位失效,不过作为面试题的追问还不错

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值