web-dev-qa-db-fra.com

Comment remplacer le paramètre CSS préfère le jeu de couleurs

J'implémente un mode sombre, comme l'ont déjà fait macOS, Windows et iOS devrait introduire un mode sombre natif.

Il existe une option native pour Safari, Chrome et Firefox, en utilisant la règle de média CSS suivante:

@media (prefers-color-scheme: dark) {
body {
    color:#fff;
    background:#333333
}

Cela identifiera automatiquement les systèmes qui sont définis sur les modes sombres et appliquera les règles CSS jointes.

Toutefois; même si les utilisateurs peuvent avoir leur système réglé en mode sombre, il se peut qu'ils préfèrent le thème clair ou par défaut d'un site Web spécifique. Il y a aussi le cas de Microsoft Edge utilisateurs qui ne prennent pas (encore) en charge @media (prefers-color-scheme. Pour la meilleure expérience utilisateur, je veux m'assurer que ces utilisateurs peuvent basculer entre les modes sombre et par défaut pour ces cas.

Existe-t-il une méthode pour cela, éventuellement avec HTML5 ou JavaScript? J'inclurais le code que j'ai essayé, mais je n'ai pu trouver aucune information sur l'implémentation de celui-ci!

12
JimmyBanks

A pris la solution fournie par @JimmyBanks et 1) a transformé la case à cocher en bouton de texte à bascule, et 2) a ajouté le changement de thème automatique lors du changement de thème du système d'exploitation.

CSS est inchangé, avec des thèmes légers stockés dans le :root et thèmes sombres stockés sous [data-theme="dark"]:

:root {
  --color_01: #000;
  --color_02: #fff;
  --color_03: #888;
}

[data-theme="dark"] {
  --color_01: #fff;
  --color_02: #000;
  --color_03: #777;
}

Le <head> JS a subi quelques modifications, notamment quelques omissions et le déplacement de data-theme instruction au bloc JS suivant:

var theme = 'light';
if (localStorage.getItem('theme')) {
  if (localStorage.getItem('theme') === 'dark') {
    theme = 'dark';
  }
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  theme = 'dark';
}

Et voici l'édition du deuxième bloc de JS, ainsi que le code HTML associé. theme_switch bascule le thème, tandis que theme_OS met automatiquement à jour le thème du site avec les modifications apportées au thème du système d'exploitation.

var theme;
function theme_apply() {
  'use strict';
  if (theme === 'light') {
    document.getElementById('theme_readout').innerHTML = 'Dark';
    document.documentElement.setAttribute('data-theme', 'light');
    localStorage.setItem('theme', 'light');
  } else {
    document.getElementById('theme_readout').innerHTML = 'Light';
    document.documentElement.setAttribute('data-theme', 'dark');
    localStorage.setItem('theme', 'dark');
  }
}
theme_apply();
function theme_switch() {
  'use strict';
  if (theme === 'light') {
    theme = 'dark';
  } else {
    theme = 'light';
  }
  theme_apply();
}
var theme_OS = window.matchMedia('(prefers-color-scheme: light)');
theme_OS.addEventListener('change', function (e) {
  'use strict';
  if (e.matches) {
    theme = 'light';
  } else {
    theme = 'dark';
  }
  theme_apply();
});
<a onclick="theme_switch()">Theme: <span id="theme_readout"></span></a>

Veuillez me faire savoir si vous avez des suggestions d'amélioration!

0
Meanderbilt

Ma Solution (3 options d'entrées radio: dark, system, light) adaptation de JimmyBanks et Meanderbilt Solution:

c'est un peu verbeux, je suppose, mais j'ai eu un peu de mal à m'enrouler autour de la tête

const themeSwitches = document.querySelectorAll('[data-color-theme-toggle]')

function removeColorThemeLocalStorage() {
  localStorage.removeItem('color-theme')
}

function saveColorTheme(colorTheme) {
  if (colorTheme === 'system') {
    removeColorThemeLocalStorage()
    return
  }
  localStorage.setItem('color-theme', colorTheme)
}

function applyColorTheme() {
  const localStorageColorTheme = localStorage.getItem('color-theme')
  const colorTheme = localStorageColorTheme || null
  if (colorTheme) {
    document.documentElement.setAttribute('data-color-theme', colorTheme)
  }
}

function themeSwitchHandler() {
  themeSwitches.forEach(themeSwitch => {
    const el = themeSwitch
    if (el.value === localStorage.getItem('color-theme')) {
      el.checked = true
    }

    el.addEventListener('change', () => {
      if (el.value !== 'system') {
        saveColorTheme(el.value)
        applyColorTheme(el.value)
      } else {
        removeColorThemeLocalStorage()
        document.documentElement.removeAttribute('data-color-theme')
      }
    })
  })
  applyColorTheme()
}
document.addEventListener('DOMContentLoaded', () => {
  themeSwitchHandler()
  applyColorTheme()
})

html {
  --hue-main: 220;
  --color-text: hsl(var(--hue-main), 10%, 25%);
  --color-text--high-contrast: hsl(var(--hue-main), 10%, 5%);
  --color-link: hsl(var(--hue-main), 40%, 30%);
  --color-background: hsl(var(--hue-main), 51%, 98.5%);
}

@media (prefers-color-scheme: dark) {
  html.no-js {
    --color-text: hsl(var(--hue-main), 5%, 60%);
    --color-text--high-contrast: hsl(var(--hue-main), 10%, 80%);
    --color-link: hsl(var(--hue-main), 60%, 60%);
    --color-background: hsl(var(--hue-main), 10%, 12.5%);
  }
}

[data-color-theme='dark'] {
  --color-text: hsl(var(--hue-main), 5%, 60%);
  --color-text--high-contrast: hsl(var(--hue-main), 10%, 80%);
  --color-link: hsl(var(--hue-main), 60%, 60%);
  --color-background: hsl(var(--hue-main), 10%, 12.5%);
}
    <div class="color-scheme-toggle" role="group" title="select a color scheme">
    <p>saved setting: <span class="theme-readout">...</span></p>
        <input type="radio" name="scheme" id="dark" value="dark" aria-label="dark color scheme"> <label for="dark">dark</label>
        <input type="radio" name="scheme" id="system" value="system" aria-label="system color scheme" checked="system"> <label for="system">system</label>
        <input type="radio" name="scheme" id="light" value="light" aria-label="light color scheme"> <label for="light">light</label>
    </div>
0
scsskid