nw-dark-mode
v1.22.17
Published
lofter dark mode library
Downloads
137
Maintainers
Keywords
Readme
nw-dark-mode
LOFTER端内深色模式SDK
原理
本SDK主要通过SVG滤镜的方式实现页面的反色,再对图片视频局部元素二次反色使其保持原样
注意
- 因为浏览器对于
html和body节点上附加CSS Filter的实现标准没有统一,在这2个节点上设置反色滤镜可能会出现兼容性的问题,具体解释可见Stack Overflow。 - 所以,使用本SDK要求页面必须有一个非
html和body元素的容器元素,并且在实例化时传入这个容器元素的选择器。(该容器宽高最好占满整个body,并且该容器的高度需要和内部元素的高度一致) - 如果
html和body高度为100%,容器元素高度也为100%,但是内容高度却大于一屏时,在使用深色模式SVG滤镜时会覆盖不全,超出容器高度的部分可能会无法反色。 - 本SDK深色模式主要基于CSS方案,所以并不要求选择器对应的元素已经加载完毕,如果想要在深色模式下进入H5就展示深色效果,可以将本SDK放入
<head>元素中,或者放在React App的useLayoutEffect中。
实现方案
相关的客户端内H5的深色模式实现方案文档见内部WIKI。
内置CSS类
nw-dark-mode深色模式下为html根节点设置的CSS类(可以配合本SDK的custom参数,自行实现深色模式的CSS适配)nw-light-mode浅色模式下为html根节点设置的CSS类,及时非客户端环境或者没有提供深浅色模式信息的客户端内也会设置(即只要没有识别到深色模式就会设置本CSS类)nw-dark-preserve为指定元素覆盖反向SVG滤镜,使其不在深色模式下被反色,可用于某些深色模式下不想被反色的图片或者icon等nw-dark-filter为指定元素手动设置SVG滤镜,只在深色模式下才有效果nw-safari判断当前浏览器环境是否为iOS safari或者iOS webview,如果是则会在html根节点设置此CSS类nw-custom-dark-mode设置darkMode.custom = true;时,会在html根节点设置的CSS类nw-filter-dark-mode设置darkMode.custom = false;时,会在html根节点设置的CSS类
太长不看版
- 复制以下代码到
html的head中,在head的第一个css文件或者标签之前。 - 修改下面代码中的
#app为当前页面的容器CSS选择器,注意避免设置为body或html
<script>
$$code$$
</script>- 如果需要在自己的应用获取或者监听App深浅色模式的切换,可以在后续的业务代码中,增加以下代码:
window.darkModeInstance && window.darkModeInstance.addChangeHandler(function (mode) {
console.log('现在的深浅色模式是', mode);
})- 如果需要切换App的深浅色模式,使用以下代码:
window.darkModeInstance.setDark();FAQ
为什么我的页面在深色模式下会有一瞬间的白色闪烁
如果没有在head的最开始使用本SDK,请检查页面中的容器以及部分主体元素的背景色,最好不要提前设置主体元素的背景色,或者在
nw-light-modeclass下设置主体元素的背景色,保证深色sdk识别完成后再完成背景色的设置深色模式下我
fixed和absolute定位的元素位置不对了(Android和Chrome浏览器)本深色SDK使用了
CSS filter实现,而该属性是会影响到容器内部元素的fixed和absolute定位的。
解决方式:- 将绝对定位的元素放到SDK初始化的容器之外,根据
nw-light-mode和nw-dark-modeclass自行适配 - 将SDK初始化的容器选择器设置为和绝对定位元素平级的其他元素,因为是纯CSS方案,选择器支持设置为
.head,.main,.footer等等,然后依然自行适配绝对定位的元素
- 将绝对定位的元素放到SDK初始化的容器之外,根据
iOS端深色模式下,我使用了
fixed、overflow:auto、transform这些CSS的元素没有应用到深色模式的滤镜这是因为iOS对于这类CSS的元素会单独为其设置一个渲染层,脱离了使用深色模式滤镜的渲染层,导致滤镜失效,此时有3种解决方案;
- 绕过:避开上述所述的几个CSS属性,使用其他属性代替(如果可以的话)
- 纯CSS:本SDK会自动识别iOS端的Safari或者webview,然后在
document上添加nw-safariclass,所以遇到上述情况,可以手动添加css适配。比如:
.footer{ position: fixed; bottom: 0; left: 0; width: 100%; height: 1rem; background: #fff; color: #333; .nw-safari.nw-dark-mode &{ background: #151515; color: #ccc } }- 配合JS: 安装
nw-detect包,引入isSafari方法,判断浏览器环境,手动为此类元素再添加一次深色模式滤镜,nw-dark-filter。此CSS类只在深色模式下有效,浅色模式无效,所以可以直接设置;但是不宜为太多元素设置此类,渲染层太多会有一定的性能问题。
import { isSafari } from 'nw-detect' function Footer() { return <div className={`footer ${isSafari() ? 'nw-dark-filter' : ''}`}>footer</div> }
自定义使用方法
- 本SDK需要先实例化后才能使用,同一页面只能实例化一次本SDK
- 使用本SDK的页面建议不设置整个页面的背景色,交由客户端容器作为背景色
- 如果页面设计上需要背景色,如果不希望出现深色模式下的背景色闪烁,可以将本SDK放入
head中初始化 - 本SDK在浅色模式下会在会在
HTML根元素上添加CSS Class:nw-light-mode,在开启深色模式时会会变成nw-dark-mode - benSDK识别到当前浏览器环境为Safari后,hiu在根元素上添加CSS Class:
nw-safari - 接入的页面可以针对此CSS class做一些适配,包括页面背景色如果一定要设置白色,最好放在SDK初始化脚本后,或者设置在
nw-light-modeclass下,避免页面在深色模式下的闪烁 - 还可以给元素设置CSS Class:
nw-dark-preserve来使元素不受SVG滤镜影响,再结合custom:true配置,实现精细的深色模式自定义适配(参照福利市集) - 可以通过读取实例的
mode属性获取当前的客户端深浅色模式,值为light|dark - 实例化时可以传递
auto、custom、onModeChange3个参数,具体见下面API解析
安装
$ npm install nw-dark-mode --save使用
可参考源码中的测试页
- es6方式引用
import DarkMode from 'nw-dark-mode';
const darkMode = new NWDarkMode();
console.log(darkMode.mode) // true
darkMode.setDark() // 切换app到深色模式,切换后,app会通知h5切换后的模式,h5再响应变化
darkMode.setLight() // 切换app到浅色模式
darkMode.dark() // h5自己切换到深色模式,不通知app
darkMode.light() // h5自己切换到浅色模式,不通知app- browser中直接使用(需要拷贝打包后的js)
<h1>测试页</h1>
<button class="nw-dark-preserve" id="switch">开关</button>
<script src="./index.umd.js"></script>
<script>
window.darkMode = new NWDarkMode()
var mode = darkMode.mode;
var switchBtn = document.getElementById('switch');
switchBtn.addEventListener('click', function () {
if (mode === 'dark') {
darkMode.light();
} else {
darkMode.dark();
}
mode = darkMode.mode;
})
</script>- 初始化后动态修改containerCssSelector和custom
import DarkMode from 'nw-dark-mode';
const darkMode = new NWDarkMode();
// ...其他代码
darkMode.custom = false;
darkMode.containerCssSelector = '.className';
/**
* 此时需要手动调用下updateView用以通知视图的更新
*/
darkMode.updateView();发布
- 在当前目录下运行
npm run build打包代码 - 在当前目录下运行
npm run doc生成最新的文档 - 提交Git信息
- 在根目录运行
npm run onlyPublish,发布组件更新
{{>main}}
