【问题标题】:How to remember color scheme once its set by user? (Simple Color Scheme)用户设置后如何记住配色方案? (简单的配色方案)
【发布时间】:2022-06-12 01:24:08
【问题描述】:

给定一个简单的配色方案,允许用户从 CSS 中预定义的一组变量(Light、Dark 等)中设置所需的主题。

有没有一种简单的方法可以让浏览器记住用户设置的方案,从而记住用户的输入并将其传递到下一页?从而无需在每个新页面上设置配色方案?

如果在浏览器重新启动或新的浏览会话后忘记了主题也没关系,并且可能会在 48 小时后忘记。

jQuery 3.6.0 库已加载到所有页面。

const setTheme = theme => document.documentElement.className = theme;
document.getElementById('scheme').addEventListener('click', ({target}) => {
  setTheme(target.getAttribute('id'));
});
html{margin: 10px}
#scheme p{ /* User Interface */
  display: inline-block;
  text-decoration: underline;
}#scheme p:hover{cursor: pointer}


:root{ /* Default Theme */
  --bgr: #eee;
  --txt: #000;
}
:root.light {
  --bgr: #ddc;
  --txt: #466;
}
:root.dark {
  --bgr: #222;
  --txt: #A75;
}
:root.blue{
  --bgr: #246;
  --txt: #eec;
}


body { /* Have something to test */
  background: var(--bgr);
  color: var(--txt);
}
<div id="scheme">
    <p id="light">Light</p>
    <p id="dark">Dark</p>
    <p id="blue">Blue</p>
    <p id="etc">Etc</p>
</div>

<h1>Click on a theme to change the color scheme!</h1>

【问题讨论】:

  • 将其放入本地存储,并在页面加载时检索它
  • 或者cookies。

标签: javascript html jquery cookies color-scheme


【解决方案1】:

有几种方法可以在页面加载之间persist data in the browser

  • cookies
  • 本地存储
  • 会话存储
  • 索引数据库

我建议使用localStorage。这里有一个很详细的comparison of the different methods


更新:

localStorage 永不过期。用户可以通过浏览器设置/开发控制台手动删除/重置localStorage。

您可以控制localStorage 中值的过期时间,方法是将过期时间戳记与值一起存储,并在每次检索该值时检查时间戳记。 (如果您只想让值在页面会话后过期,请使用 sessionStorage。)

amplify.store 是浏览器存储 API 的包装器。它可以让你设置一个可选的过期时间。

【讨论】:

  • 感谢您提供有关浏览器中数据保存选项的不同方法的答案。 localStorage 将在哪个时间点(在某个时间或在哪些活动之后)消失、被刷新、清理或删除或只是重置?请将此信息添加到您的答案中。
  • @Sam localStorage 永不过期。我在答案中添加了更多信息。
  • 感谢您更清楚地了解 localStorage 的无限寿命!饼干会吃醋。
【解决方案2】:

试试这个简单的解决方法:从本地存储中保存、加载和选择主题。 本地存储在 sn-ps 或沙盒中不起作用。

window界面的localStorage只读属性允许你访问一个Storage对象作为Document的来源;存储的数据跨浏览器会话保存。 MDN documentation

document.addEventListener('DOMContentLoaded', function () {
  // Initial array of theme color names
  const themeNameArray = ['light', 'dark', 'blue', 'etc'];
  // Get html node (html tag)
  const htmlNode = document.documentElement;
  // Get color (value) from local storage
  const getLocalStorageTheme = localStorage.getItem('theme');

  const setTheme = theme => {
    // Set class to html node
    htmlNode.className = theme;
    // Set theme color to local storage
    localStorage.setItem('theme', theme);
  };

  // Find current theme color (value) from array
  const findThemeName = themeNameArray.find(theme => theme === getLocalStorageTheme);

  // If local storage empty
  if (!getLocalStorageTheme) {
    // Set the value for default theme
    setTheme('etc');
  } else {
    // Set loaded theme
    setTheme(findThemeName);
  }

  document.getElementById('scheme').addEventListener('click', ({ target }) => {
    // Getting ID from an attribute
    const id = target.getAttribute('id');
    // Find current theme color (value) from array
    const findThemeName = themeNameArray.find(theme => theme === id);
    setTheme(findThemeName);
  });
});

document.addEventListener('DOMContentLoaded', function() {
  const themeNameArray = ['light', 'dark', 'blue', 'etc'];
  const htmlNode = document.documentElement;
  const getLocalStorageTheme = localStorage.getItem('theme');

  const setTheme = theme => {
    htmlNode.className = theme;
    localStorage.setItem('theme', theme);
  };

  const findThemeName = themeNameArray.find(theme => theme === getLocalStorageTheme);

  // If local storage empty
  if (!getLocalStorageTheme) {
    // Set the value for default theme
    setTheme('etc');
  } else {
    // Set loaded theme
    setTheme(findThemeName);
  }

  document.getElementById('scheme').addEventListener('click', ({
    target
  }) => {
    const id = target.getAttribute('id');
    const findThemeName = themeNameArray.find(theme => theme === id);
    setTheme(findThemeName);
  });
});
html {
  margin: 10px;
}

#scheme p {
  /* User Interface */
  display: inline-block;
  text-decoration: underline;
}

#scheme p:hover {
  cursor: pointer;
}

:root {
  /* Default Theme */
  --bgr: #eee;
  --txt: #000;
}

:root.light {
  --bgr: #ddc;
  --txt: #466;
}

:root.dark {
  --bgr: #222;
  --txt: #a75;
}

:root.blue {
  --bgr: #246;
  --txt: #eec;
}

body {
  /* Have something to test */
  background: var(--bgr);
  color: var(--txt);
}
<div id="scheme">
  <p id="light">Light</p>
  <p id="dark">Dark</p>
  <p id="blue">Blue</p>
  <p id="etc">Etc</p>
</div>

<h1>Click on a theme to change the color scheme!</h1>

【讨论】:

  • 非常感谢@Anton!你是第一个回答这个问题的!您能否在尚未注释的代码部分上方添加几行注释,以便更好地为社区阐明您的代码?
  • @Sam 添加了附加 cmets。代码段已更新。
【解决方案3】:

使用matchMediaprefers-color-scheme,您可以根据用户的系统范围偏好应用默认主题。如果用户启用了根据一天中的时间或通过其设备上的光传感器启用自动切换,这将自动调整。

然后,如果他们选择覆盖它,请将他们的选择保存在 localStorage 中。在用户清除您的源的存储之前,此首选项将保持不变。

<!DOCTYPE html>
<head>
  <title> Theme Selector Test </title>
  <style>
    :root.default { --bgr: #eee; --txt: #000; }
    :root.light { --bgr: #ddc; --txt: #446; }
    :root.dark { --bgr: #222; --txt: #a75; }
    :root.blue { --bgr: #246; --txt: #eec; }
    body { background: var(--bgr); color: var(--txt); margin: 1.5rem; }
  </style>
  <script>
    function setTheme(theme) {
      if (theme == 'auto') {
        localStorage.removeItem('theme');
        loadTheme(null);
      } else {
        localStorage.setItem('theme', theme);
        applyTheme(theme);
      }
    }

    function loadTheme(theme) {
      let prefersDark = matchMedia('(prefers-color-scheme: dark)');
      prefersDark.addEventListener('change', event => loadTheme());
      theme = localStorage.getItem('theme');
      theme ??= (prefersDark.matches) ? 'dark' : 'default';
      applyTheme(theme);
    }

    function applyTheme(theme) {
      document.documentElement.className = theme;
    }

    window.setTheme = setTheme;

    loadTheme();
  </script>
</head>
<body>
  <h1> Select a theme to change the color scheme! </h1>
  <select id="scheme">
    <option value="auto">Auto</option>
    <option value="default">Default</option>
    <option value="light">Light</option>
    <option value="dark">Dark</option>
    <option value="blue">Blue</option>
  </select>
  <script>
    let selector = document.getElementById('scheme');
    selector.value = localStorage.getItem('theme') || 'auto';
    selector.addEventListener('click', event => window.setTheme(selector.value));
  </script>
</body>

请参阅this answer,了解有关如何模拟系统范围偏好以进行测试的说明。

正如@Anton 所提到的,localStorage 由于沙盒,在 Stack Overflow 上的 sn-ps 中不起作用,因此我将其编写为整页示例,以演示在实际中实现它的最佳方法-世界环境。

我也有 published 的 ES 模块版本。实现本文中演示的内联版本会更好地提高性能,但如果您想避免污染全局范围,则模块版本会更好。

我在示例中使用了&lt;select&gt; 元素,因为这可能是大多数用户在未来发现它时可能想要使用它的方式。要显示您在问题中显示的选项,您可以如下所示实施。请注意,我已将 &lt;p&gt; 标记替换为 &lt;button&gt; 以获得更好的可访问性。我还在单击处理程序中添加了一个额外的检查,以避免在单击容器 &lt;div&gt; 的背景区域时调用 setTheme

在你的 CSS 中:

#scheme button {
  border: 0;
  background: none;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
 }

在您的 HTML &lt;body&gt; 中:

<div id="scheme">
  <button id="auto">Auto</button>
  <button id="default">Default</button>
  <button id="light">Light</button>
  <button id="dark">Dark</button>
  <button id="blue">Blue</button>
</div>
<h1>Click on a theme to change the color scheme!</h1>
<script>
  let selector = document.getElementById('scheme');
  selector.addEventListener('click', event => {
    if (event.target == selector) { return; }
    window.setTheme(event.target.id);
  });
</script>

【讨论】:

  • 很棒的完整的 HTML 阐述!我在将您当前的最新代码恢复为我的问题格式时遇到问题,并且始终可以水平地看到可点击的东西。我不想要选择下拉选项。我希望&lt;p&gt; 元素始终彼此相邻可见。它使用符号和 svg 等图形进行编辑和布局比通过下拉选项> 选择一个然后再次打开下拉选项的点击次数更少。是否有可能在您最新的答案中实现问题的格式?谢谢!
  • 查看我的最新编辑,了解如何实现它,如您的问题所示。
猜你喜欢
  • 1970-01-01
  • 2010-12-28
  • 2012-02-12
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 2011-01-27
相关资源
最近更新 更多