代码之家  ›  专栏  ›  技术社区  ›  JimmyBanks

如何过度使用css首选配色方案设置

  •  0
  • JimmyBanks  · 技术社区  · 6 年前

    有一个本机选项 Safari , Chrome ,和 Firefox

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

    这将自动识别设置为暗模式的系统,并应用所附的css规则。

    Microsoft Edge 尚未支持的用户 @media (prefers-color-scheme . 为了获得最佳的用户体验,我想确保这些用户可以在这些情况下的暗模式和默认模式之间切换。

    0 回复  |  直到 6 年前
        1
  •  15
  •   JimmyBanks    6 年前

    我已经确定了一个合适的解决方案,如下所示:

    CSS将使用变量和主题:

    // root/default variables
    :root {
        --font-color: #000;
        --link-color:#1C75B9;
        --link-white-color:#fff;
        --bg-color: rgb(243,243,243);
    }
    //dark theme
    [data-theme="dark"] {
        --font-color: #c1bfbd;
        --link-color:#0a86da;
        --link-white-color:#c1bfbd;
        --bg-color: #333;
    }
    

    然后在必要时调用变量,例如:

    //the redundancy is for backwards compatibility with browsers that do not support CSS variables.
    body
    {
        color:#000;
        color:var(--font-color);
        background:rgb(243,243,243);
        background:var(--bg-color);
    }
    

    JavaScript用于标识用户设置了哪个主题,或者如果用户已经覆盖了OS主题,以及在两者之间切换,这将包含在html输出之前的头中 <body>...</body> :

    //determines if the user has a set theme
    function detectColorScheme(){
        var theme="light";    //default to light
    
        //local storage is used to override OS theme settings
        if(localStorage.getItem("theme")){
            if(localStorage.getItem("theme") == "dark"){
                var theme = "dark";
            }
        } else if(!window.matchMedia) {
            //matchMedia method not supported
            return false;
        } else if(window.matchMedia("(prefers-color-scheme: dark)").matches) {
            //OS theme setting detected as dark
            var theme = "dark";
        }
    
        //dark theme preferred, set document with a `data-theme` attribute
        if (theme=="dark") {
             document.documentElement.setAttribute("data-theme", "dark");
        }
    }
    detectColorScheme();
    

    这个javascript用于在设置之间切换,它不需要包含在页面的标题中,但是可以包含在任何位置

    //identify the toggle switch HTML element
    const toggleSwitch = document.querySelector('#theme-switch input[type="checkbox"]');
    
    //function that changes the theme, and sets a localStorage variable to track the theme between page loads
    function switchTheme(e) {
        if (e.target.checked) {
            localStorage.setItem('theme', 'dark');
            document.documentElement.setAttribute('data-theme', 'dark');
            toggleSwitch.checked = true;
        } else {
            localStorage.setItem('theme', 'light');
            document.documentElement.setAttribute('data-theme', 'light');
            toggleSwitch.checked = false;
        }    
    }
    
    //listener for changing themes
    toggleSwitch.addEventListener('change', switchTheme, false);
    
    //pre-check the dark-theme checkbox if dark-theme is set
    if (document.documentElement.getAttribute("data-theme") == "dark"){
        toggleSwitch.checked = true;
    }
    

    <label id="theme-switch" class="theme-switch" for="checkbox_theme">
        <input type="checkbox" id="checkbox_theme">
    </label>
    

    通过使用CSS变量和JavaScript,我们可以自动确定用户主题,应用它,并允许用户过度使用它。[截至本文撰写之时(2019/06/10),只有Firefox和Safari支持自动主题检测]

        2
  •  1
  •   DenverCoder9    5 年前

    你可以使用我的自定义元素 <dark-mode-toggle> 最初遵循用户的 prefers-color-scheme 设置,但这也允许用户(永久或临时)覆盖它。切换既适用于单独的CSS文件,也适用于切换的类。这个 README 有两种方法的示例。

        3
  •  0
  •   x381209    6 年前

    我会为一个暗主题创建第二个CSS文件并使用

    @media (prefers-color-scheme: dark) {
         @import url("dark.css");
    }
    

    然后,一些 these 如果用户选择暗模式,则使用JavaScript添加。如果给link元素一个ID(或全局作用域),也可以用JS删除它。

        4
  •  0
  •   Meanderbilt    5 年前

    采用了@JimmyBanks提供的解决方案,1)将复选框变成了一个切换文本按钮,2)添加了操作系统主题更改时的自动主题切换。

    :root 黑暗的主题 [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;
    }
    

    这个 <head> data-theme 对后续JS块的语句:

    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';
    }
    

    theme_switch 切换主题,同时 theme_OS 使用对OS主题的更改自动更新站点的主题。

    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>
    

        5
  •  0
  •   scsskid    5 年前

    我的解决方案(无线电输入中的3个选项:暗、系统、光)JimmyBanks和Meanderbilt解决方案的自适应:

    我想这有点冗长,但我努力想把我的头裹起来

    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>