Electron 如何快速适配MacOS暗色主题
随着macOS Mojave的最新公开发布,作为一名开发人员,我相信您已经收到了大量要求为应用制作深色主题版本的请求。
目标:用最少的工作量完成3个主题
主题
浅色、深色和浅色-深色侧边栏是我们最初寻找的主题。这个技巧的好处在于我们只需要两个基本主题,第三个是两个主题的混合,并且只需要一个额外的CSS选择器。
最少的工作
以最小的努力,我不仅意味着只能通过编辑现有CSS变量来添加新主题,而且还可以从性能的角度来添加新主题。不要让HTML知道当前主题,并且在更改主题时不需要任何形式的重新渲染。
额外优势:当您要做的只是通过Web控制台change在<html>
上更改属性时,非常容易快速调试。

我们不想要FOUC!
有什么比看到一个亮的主题出现几毫秒然后切换到一个暗的主题更糟糕的呢?没有是更糟。
Electron
为了避免FOUC,我们将在BrowserWindow上使用localStorage和预加载的脚本。一旦你的应用程序启动,预先加载的脚本被加载,虽然<html>
还不能被访问,window
可以。
使用Electron提供的 systemPreferences API,我们可以知道操作系统当前是否在使用暗模式,并且可以订阅主题更改事件。
const { remote } = require('electron')
if (process.platform == 'darwin') {
const { systemPreferences } = remote
const setOSTheme = () => {
let theme = systemPreferences.isDarkMode() ? 'dark' : 'light'
window.localStorage.os_theme = theme
//
// Defined in index.html, so undefined when launching the app.
// Will be defined for `systemPreferences.subscribeNotification` callback.
//
if ('__setTheme' in window) {
window.__setTheme()
}
}
systemPreferences.subscribeNotification(
'AppleInterfaceThemeChangedNotification',
setOSTheme,
)
setOSTheme()
}
然后我们将在index.html中定义_settheme
函数,并确保在启动应用程序时调用它。在第一次运行时,预加载的脚本已经设置了localStorage.os_theme
,所以我们可以使用它并尽快在<html>
上设置一个属性,特别是在加载样式之前。我们还将先发制人地读取localStorage.user_theme
,如果你想让用户选择他们自己的主题,而不是仅仅依赖于操作系统。
<!DOCTYPE html>
<head>
<script>
window.__setTheme = () => {
let userTheme = localStorage.user_theme
let OSTheme = localStorage.os_theme
let defaultTheme = 'light'
document.documentElement.setAttribute(
'data-theme',
userTheme || OSTheme || defaultTheme,
)
}
__setTheme()
</script>
<link rel="stylesheet" href="application.css">
</head>
<body></body>
</html>
CSS
我们将利用一些技术:CSS变量、特殊性和属性选择器。
/* Default variables */
:root {
--blue-color: blue;
--green-color: green;
}
[data-theme^="light"],
[data-theme] [data-theme^="light"] {
--main-color: #000;
--background-color: #fff;
--box-color: lightgrey;
}
[data-theme^="dark"],
[data-theme] [data-theme^="dark"],
[data-theme="light-dark-sidebar"] nav {
--blue-color: #1da1f2;
--main-color: #fff;
--background-color: #000;
--sidebar-color: #333;
--box-color: grey;
}
额外的特异性选择器[data-theme] [data-theme =“ light”]
这是使主题相互嵌入的一种方式。您可以通过设置data-theme属性来强制应用的任何部分具有给定的主题。 注意:否则,即使您在HTML的任何位置添加data-theme =“ light”
,它仍将使用<html data-theme =“ dark”>
变量。因为具有相同的特异性,因此在CSS中声明了深色变量。那只是适用的旧的级联规则。

属性选择器 ^=“light”
也就是说,light
和 light-dark-sidebar
都使用相同的基本主题。
作用域的变量 [data-theme="light-dark-sidebar"] nav
那就是拥有主题变体,而不必让HTML意识到它。对于该主题,使用浅色主题,但是元素将使用深色变量。这样,您在更改主题时无需重新渲染HTML的任何部分,只需更新和Voila!
macOS Mojave
即使转换只是CSS,Mojave上的转换也是100%无缝的。 macOS冻结当前帧并在幕后呈现新布局。准备就绪后,它将淡入淡出这两种布局,使您的应用看起来像Finder一样原生。