当前位置: 首页 > Web前端 > HTML

在浏览器中检测暗模式

时间:2023-03-29 11:29:15 HTML

前言深色模式(DarkMode),又称深色模式,顾名思义,它给人最直观的感觉,就是黑色。而“深色模式”要达到理想的视觉体验,不仅仅是简单的将背景颜色变黑,将文字变白就是这么简单的答案。在Google的MaterialDesign设计指南中列出的“深色模式”的设计规范中,第一项就是“不要使用100%纯黑色”。前端工程师需要和设计师沟通,如何做一个有利于用户体验、成本合理的“黑模式”方案;另一方面,我们也需要关心如何合理的使用CSS组合来实现“深色模式”。那么,前端如何检测当前运行环境因“深色模式”呢?并根据当前的颜色模式,编写相应的CSS?与“深色模式”相关的CSSMediaQuery当前大多数浏览器或其他WebView都支持CSSMediaQueryprefers-coloraboutdarkmode-scheme,其格式如下:@media(prefers-color-scheme:)其中,light表示“亮模式”,dark表示“暗模式”。在CSS中使用/*灯光模式*/@media(prefers-color-scheme:light){body{color:black;背景色:白色;}}/*深色模式*/@media(prefers-color-scheme:dark){body{color:white;背景色:黑色;相应的,你也可以在CSSinJS解决方案中使用这个,比如styled-components。通过JS检测当前环境是否处于深色模式在我的开发工作中,基于WebKit引擎中检测“当前环境是否处于深色模式”的需求,我参与了其中。如何通过JS检测当前环境是否处于“深色模式”?由于CSS是通过MediaQuery来判断的。很自然地,我们会想到使用[matchMedia]API来判断。window.matchMedia('')返回一个listenable-like对象[MediaQueryList],它继承自[EventTarget],也就是说你可以直接通过它获取最新的MediaQuery检测情况://detectifonlightmodevarisLight=window.matchMedia('(prefers-color-scheme:light)').matches;//检测是否处于暗模式varisDarkMode=window.matchMedia('(prefers-color-scheme:dark)').matches;对于主流浏览器,[matchMedia]API支持比较OK,Chrome>=9,Safari>=5.1都支持。更多浏览器支持请参考【CanIusematchMedia】监听当前环境颜色模式的变化。同时,window.matchMedia('')返回的[MediaQueryList]有addEventListener/removeEventListener接口。当环境的MediaQuery属性发生变化时,[MediaQueryList]将发出change事件。这意味着您可以监听其相关的MediaQuery://listenable-likeobject[`MediaQueryList`]varmqList=window.matchMedia('');mqList.addEventListener('change',(event)=>{//匹配的preferif(event.matches){}else{//不匹配的prefer}});所以,你可以检测环境的颜色模式何时改变:varmqList=window.matchMedia('(prefers-color-scheme:dark)');mqList.addEventListener('change',(event)=&g吨;{//是黑暗模式if(event.matches){}else{//不是黑暗模式}});MediaQueryList对象的兼容性问题参考兼容性列表,我们可以发现一些问题。比如IE和Opera在不支持addEventListener(...)时,使用一个对象作为EventListener传入Safari,参考MDN上兼容性列表上的说明:BeforeSafari14,[MediaQueryList]isbasedonEventTarget,所以你必须使用addListener()和removeListener()来观察媒体查询列表。对于Safari<14,[MediaQueryList]存在以下兼容性问题,没有MediaQueryList.addEventListener,只有[MediaQueryList.addListener],其签名为addListener(func),参考这里没有MediaQueryList.removeEventListener,只有[MediaQueryList.removeListener】,其签名为addListener(func),仅指InternetExplorerIE>=10版本支持[MediaQueryList]特性。在IE上,[MediaQueryList]对象不是从[EventTarget]继承的。它支持[MediaQueryList.addListener]和[MediaQueryList.removeListener]在处理兼容性问题时很容易想到。我们只需要稍微改动一下上面的代码就可以在Safari<14,IE>=10的环境下流畅运行:varmqList=window.matchMedia('');//检测MediqQueryList对象上是否存在addEventListener方法if(mqList.addEventListener){mqList.addEventListener('change',(event)=>{});}elseif(mqList.addListener){//否则检查MediqQueryList对象上是否有addListenermqList.addListener((event)=>{});}removeEventListener/removeListener的处理类似。我们可以使用函数observeMediaChange(medieQuery,listener)来隐藏处理细节:/***@param{MediaQueryList}mqList*@param{(((this:MediaQueryList,ev:MediaQueryListEvent)=>any)}listener*/functionobserveMediaChange(mqList,listener){让disposeFunc=()=>{};if(mqList.addEventListener&&mqList.removeEventListener){mqList.addEventListener('change',listener);disposeFunc=()=>{mqList.removeEventListener('change',listener);};}elseif(mqList.addListener&&mqList.removeListener){mqList.addListener(listener);disposeFunc=()=>{mqList.removeListener(listener);};}returndisposeFunc;}}varmqList=window.matchMedia('');observeMediaChange(mqList,(event)=>{//是黑暗模式if(event.matches){}else{//不是黑暗模式}});ReactHooks封装我们可以使用window.matchMedia('')返回的[MediaQueryList]封装一个即时敏感的useIsDarkModeHooks:import{useState,useEffect}from'react';functioncheckIsDarkMode(){try{returnwindow.matchMedia('(prefers-color-scheme:dark)').matches;}catch(err){返回错误;}}functionuseIsDarkMode(){const[isDarkMode,setIsDarkMode]=useState(checkIsDarkMode());useEffect(()=>{constmqList=window.matchMedia('(prefers-color-scheme:dark)');/****@param{MediaQueryListEvent}event*/constlistener=(event)=>{setIsDarkMode(event.matches);};mqList.addEventListener('change',listener);return()=>{mqList.removeEventListener('change',listener);};},[]);returnisDarkMode;}可以像这样在React功能组件中使用:functionFoo(){constisDarkMode=useIsDarkMode();返回...

;}注意上面useIsDarkMode的实现没有考虑浏览器兼容性问题,如果需要在Safari<14这样的环境下运行的话,你可以使用observeMediaChange来修改useIsDarkMode的内部实现。延伸阅读[CanIusematchMedia][MediaQueryList]JobOpportunitiesrichardo2016#gmail.com。我可以帮助推荐以下公司:阿里巴巴(深圳、杭州、北京、上海、成都)网易(杭州)腾讯(成都、深圳)字节跳动(杭州)