Aller au contenu principal

Mode Sombre

Vue d'ensemble

Mettre à jour automatiquement les interfaces natives

Les "interfaces natives" incluent le sélecteur de fichiers, la bordure de fenêtre, les dialogues, les menus contextuels et plus encore - tous les éléments de l'interface utilisateur qui provient de votre système d'exploitation et pas de votre application. Le comportement par défaut est d'opter pour le thème automatique de l'OS.

Mettre à jour automatiquement vos propres interfaces

Si votre application dispose de son propre mode sombre, vous devrez l’activer et le désactiver en synchronisation avec le paramètre de mode sombre du système. Vous pouvez le faire en utilisant la media query CSS prefers-color-scheme.

Mettre à jour manuellement vos propres interfaces

Si vous souhaitez basculer manuellement entre les modes clair/sombre, vous pouvez le faire en indiquant le mode souhaité au niveau de la propriété themeSource du module nativeTheme. La valeur de cette propriété sera propagée à votre processus de rendu. Toutes les règles CSS relatives à prefers-color-scheme seront mises à jour en conséquence.

paramètres macOS

Dans macOS 10.14 Mojave, Apple a introduit un nouveau mode sombre à l'échelle du système pour tous les ordinateurs macOS. Si votre application Electron a un mode sombre, vous pouvez le faire suivre le réglage du mode sombre à l'échelle du système en utilisant l'API nativeTheme.

Dans macOS 10.15 Catalina, Apple a introduit une nouvelle option de mode sombre « automatique » pour tous les ordinateurs macOS. Afin que les API nativeTheme.shouldUseDarkColors et Tray fonctionnent correctement dans ce mode sur Catalina, vous devez utiliser une version d'Electron >=7.0.0, ou mettre NSRequiresAquaSystemAppearance à false dans votre fichier Info.plist pour les anciennes versions. Both Electron Packager and Electron Forge have a darwinDarkModeSupport option to automate the Info.plist changes during app build time.

Si vous ne souhaitez pas choisir cette option tout en utilisant une version d'’Electron > 8.0.0, vous devez définir la clé NSRequiresAquaSystemAppearance à true dans le fichier Info.plist. . Veuillez noter qu’Electron 8.0.0 et versions ultérieures ne vous permettront pas de vous désinscrire de ce thème, en raison de l’utilisation du SDK macOS 10.14.

Exemple

Cet exemple illustre une application Electron qui tire ses couleurs de thème du nativeTheme. De plus, il fournit des contrôles de basculement de thème et des contrôles de réinitialisation en utilisant les canaux IPC.

const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron/main')
const path = require('node:path')

function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

win.loadFile('index.html')
}

ipcMain.handle('dark-mode:toggle', () => {
if (nativeTheme.shouldUseDarkColors) {
nativeTheme.themeSource = 'light'
} else {
nativeTheme.themeSource = 'dark'
}
return nativeTheme.shouldUseDarkColors
})

ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSource = 'system'
})

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

Comment cela fonctionne ?

Commençons avec le fichier index.html:

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="stylesheet" type="text/css" href="./styles.css">
</head>
<body>
<h1>Hello World!</h1>
<p>Current theme source: <strong id="theme-source">System</strong></p>

<button id="toggle-dark-mode">Toggle Dark Mode</button>
<button id="reset-to-system">Reset to System Theme</button>

<script src="renderer.js"></script>
</body>
</html>

Et le fichier styles.css:

styles.css
@media (prefers-color-scheme: dark) {
body { background: #333; color: white; }
}

@media (prefers-color-scheme: light) {
body { background: #ddd; color: black; }
}

L'exemple produit une page HTML avec quelques éléments. L'élément <strong id="theme-source"> indique quel thème est actuellement sélectionné, et les deux éléments <button> sont les contrôles. Le fichier CSS utilise la media query prefers-color-scheme afin de définir les couleurs d'arrière-plan de l'élément <body> et les couleurs du texte.

Le script preload.js ajoute une nouvelle API à l'objet window appelé darkMode. Cette API expose deux canaux IPC au processus de rendu, 'dark-mode:toggle' et 'dark-mode:system'. Il assigne également deux méthodes, toggle et system, qui passent des messages du moteur de rendu au processus principal.

preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('darkMode', {
toggle: () => ipcRenderer.invoke('dark-mode:toggle'),
system: () => ipcRenderer.invoke('dark-mode:system')
})

Maintenant, le processus de rendu peut communiquer avec le processus principal de manière sécurisée et effectuer les mutations nécessaires à l'objet nativeTheme.

Le fichier renderer.js est responsable du contrôle de la fonctionnalité <button>.

renderer.js
document.getElementById('toggle-dark-mode').addEventListener('click', async () => {
const isDarkMode = await window.darkMode.toggle()
document.getElementById('theme-source').innerHTML = isDarkMode ? 'Dark' : 'Light'
})

document.getElementById('reset-to-system').addEventListener('click', async () => {
await window.darkMode.system()
document.getElementById('theme-source').innerHTML = 'System'
})

En utilisant addEventListener, le fichier renderer.js ajoute un event listeners sur 'click' à chaque élément bouton. Chaque gestionnaire d'écouteur d'événements effectue des appels vers les méthodes API window.darkMode respectives.

Enfin, le fichier main.js représente le processus principal et contient l'API nativeTheme.

const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
const path = require('node:path')

const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

win.loadFile('index.html')

ipcMain.handle('dark-mode:toggle', () => {
if (nativeTheme.shouldUseDarkColors) {
nativeTheme.themeSource = 'light'
} else {
nativeTheme.themeSource = 'dark'
}
return nativeTheme.shouldUseDarkColors
})

ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSource = 'system'
})
}

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

Les méthodes ipcMain.handle sont la façon dont le processus principal répond aux événements de click des boutons de la page HTML.

La méthode gestionnaire de canaux IPC 'dark-mode:toggle' vérifie la propriété booléenne shouldUseDarkColors , définit la themeSource correspondante , puis renvoie la propriété shouldUseDarkColors actuelle. En revenant un peu sur l’écouteur d’événements du processus de rendu pour ce canal IPC, la valeur de retour de ce gestionnaire est utilisée pour affecter le texte adequate à l’élément <strong id='theme-source'> .

La méthode gestionnaire de canaux IPC 'dark-mode:system' affecte la chaîne 'system' à la themeSource et ne renvoie rien. Cela correspond également à l’écouteur d’événement correspondant du processus de rendu, puisque on attend la méthode sans aucune valeur de retour.

Exécutez l’exemple à l’aide d’Electron Fiddle, puis cliquez sur le bouton « Basculer le mode sombre »; l’application devrait commencer à alterner entre un fond clair et un fond sombre.

Thème Sombre