有意思的面试题-如何在网页置灰的前提下,保持部分元素彩色 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
woniuppp
V2EX    程序员

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

  •  
  •   woniuppp
    shengxinjing 2022-12-06 23:19:20 +08:00 2170 次点击
    这是一个创建于 1046 天前的主题,其中的信息可能已经有所发展或是发生改变。

    网页置灰方案讨论

    如何在网页置灰的前提下,保持部分元素彩色

    在线体验

    本文视频版链接

    最近哀悼日,网页端如何一键变灰已经有很多实现方式了,但是我看到一个推文很有意思,是一个不错的面试题

    现在网页置灰已经不仅仅是一行 css 的事了,如何在网页置灰的前提下,部分元素保持彩色,这是一个不错的 system design 题

    欢迎加我,畅聊前端

    一键变灰

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

    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 就可以了

    01.gif

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

    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, 实现一个只置灰首屏的效果,不过我感觉没啥必要

    02.gif

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

    05.gif

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

    元素遍历标记

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

    image.png

    image.png

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

    06.jpeg

     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 = true let parent = v.parentNode while(parent && !parent.colorful){ parent.colorful = true parent = 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 可能会导致部分元素的定位失效,不过作为面试题的追问还不错

    04.gif

    总结

    作为面试题来说,考察了面试者的 css ,js 的 dom 遍历,递归思想,很不错的入门题

    12 条回复    2022-12-09 23:04:30 +08:00
    chrisqin
        1
    chrisqin  
       2022-12-06 23:25:21 +08:00 via iPhone   4
    总结来说为了皇上不死无所不用其极。
    me221
        2
    me221  
       2022-12-06 23:53:02 +08:00   1
    为了某人, 前端难度一下子就提升了
    efaun
        3
    efaun  
       2022-12-07 00:49:55 +08:00
    title 里包含"刁"字, 浏览器会自动恢复为彩色
    m1klos
        4
    m1klos  
       2022-12-07 08:57:52 +08:00
    独彩者
    wangnimabenma
        5
    wangnimabenma  
       2022-12-07 09:52:11 +08:00
    挺好的,再灰一次?
    llzzll1234
        6
    llzzll1234  
       2022-12-07 09:52:47 +08:00   2
    本来好好的技术讨论贴,楼上几个非要秀一下存在感
    Chemist
        7
    Chemist  
       2022-12-07 11:37:40 +08:00   1
    《如何阉割太监能避免临床感染》

    本来好好的学术帖
    Junh
        8
    Junh  
       2022-12-07 11:38:25 +08:00
    露出鸡脚了,小黑子
    lookStupiToForce
        9
    lookStupiToForce  
       2022-12-07 14:33:31 +08:00
    小鸡子露出黑脚了,明天出庭记得戴上 v2ex
    MMMMMMMMMMMMMMMM
        10
    MMMMMMMMMMMMMMMM  
       2022-12-07 23:11:17 +08:00
    你很会蹭热点,可惜并没有出现你预想中的点击量和热议效果
    woniuppp
        11
    woniuppp  
    OP
       2022-12-08 18:06:39 +08:00
    @MMMMMMMMMMMMMMMM 谢谢夸奖,确实是个不错的面试题
    cppgohan
        12
    cppgohan  
       2022-12-09 23:04:30 +08:00
    是个不错的面试题, chatgpt 好像还不会做, 它给到的答案类似
    html{
    filter:grayscale(100%);
    }
    .not-gray{
    filter:none;
    }
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2608 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 12:24 PVG 20:24 LAX 05:24 JFK 08:24
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86