Jim*_*nks 5 html javascript css media-queries
我正在实现暗模式,因为macOS,Windows已经实现了暗模式,并且iOS有望引入本机暗模式。
使用以下CSS媒体规则为Safari,Chrome和提供本机选项Firefox:
@media (prefers-color-scheme: dark) {
body {
color:#fff;
background:#333333
}
Run Code Online (Sandbox Code Playgroud)
这将自动识别设置为暗模式的系统,并应用随附的CSS规则。
然而; 即使用户可能将系统设置为暗模式,也可能是他们偏爱特定网站的浅色或默认主题。还有一些Microsoft Edge用户不支持的情况@media (prefers-color-scheme。为了获得最佳的用户体验,我想确保这些用户可以在这些情况下的黑暗模式和默认模式之间切换。
有没有可以使用HTML5或JavaScript执行的方法?我会包含尝试过的代码,但是无论如何我都找不到任何信息!
phi*_*ole 27
使用 CSS 变量,在媒体查询中设置默认值和相反值。还要设置两个类中的值,并实现一个在单击时切换这些类的切换开关。
\n默认情况下,根据系统配色方案使用自动模式。使用拨动开关切换至手动模式。刷新页面(或从 html 元素中删除该类)后,它返回自动模式。
\n// toggle to switch classes between .light and .dark\n// if no class is present (initial state), then assume current state based on system color scheme\n// if system color scheme is not supported, then assume current state is light\nfunction toggleDarkMode() {\n if (document.documentElement.classList.contains("light")) {\n document.documentElement.classList.remove("light")\n document.documentElement.classList.add("dark")\n } else if (document.documentElement.classList.contains("dark")) {\n document.documentElement.classList.remove("dark")\n document.documentElement.classList.add("light")\n } else {\n if (window.matchMedia && window.matchMedia(\'(prefers-color-scheme: dark)\').matches) {\n document.documentElement.classList.add("dark")\n } else {\n document.documentElement.classList.add("light")\n }\n }\n}Run Code Online (Sandbox Code Playgroud)\r\n/* automatic/manual light mode */\n:root, :root.light {\n --some-value: black;\n --some-other-value: white;\n}\n\n/* automatic dark mode */\n/* \xe2\x9d\x97\xef\xb8\x8f keep the rules in sync with the manual dark mode below! */\n@media (prefers-color-scheme: dark) {\n :root {\n --some-value: white;\n --some-other-value: black;\n }\n}\n\n/* manual dark mode \n/* \xe2\x9d\x97\xef\xb8\x8f keep the rules in sync with the automatic dark mode above! */\n:root.dark {\n --some-value: white;\n --some-other-value: black;\n}\n\n/* use the variables */\nbody {\n color: var(--some-value);\n background-color: var(--some-other-value);\n}Run Code Online (Sandbox Code Playgroud)\r\n<button onClick="toggleDarkMode()">Toggle</button>\n<h1>Hello world!</h1>Run Code Online (Sandbox Code Playgroud)\r\nBha*_*har 10
我使用博客 mybyways 找到了一个替代解决方案,该解决方案在其他地方没有提到,但对我有用。仅当 html 使用prefers-color-scheme css 媒体类时这才有用。
与其他答案不同,它使用样式表的规则来附加类(而不是从 classList 添加或删除“dark”或“light”)
默认情况下,它采用操作系统设置的样式并在切换时覆盖它。我在 Google Chrome 实验室尝试过,但没有成功。
function setPreferredColorScheme(mode = "dark") {
console.log("changing")
for (var i = document.styleSheets[0].rules.length - 1; i >= 0; i--) {
rule = document.styleSheets[0].rules[i].media;
if (rule.mediaText.includes("prefers-color-scheme")) {
console.log("includes color scheme")
switch (mode) {
case "light":
console.log("light")
rule.appendMedium("original-prefers-color-scheme");
if (rule.mediaText.includes("light")) rule.deleteMedium("(prefers-color-scheme: light)");
if (rule.mediaText.includes("dark")) rule.deleteMedium("(prefers-color-scheme: dark)");
break;
case "dark":
console.log("dark")
rule.appendMedium("(prefers-color-scheme: light)");
rule.appendMedium("(prefers-color-scheme: dark)");
if (rule.mediaText.includes("original")) rule.deleteMedium("original-prefers-color-scheme");
break;
default:
console.log("default")
rule.appendMedium("(prefers-color-scheme: dark)");
if (rule.mediaText.includes("light")) rule.deleteMedium("(prefers-color-scheme: light)");
if (rule.mediaText.includes("original")) rule.deleteMedium("original-prefers-color-scheme");
}
break;
}
}
}Run Code Online (Sandbox Code Playgroud)
@media (prefers-color-scheme: light) {
:root {
color: pink;
background-color: yellow;
}
}
@media (prefers-color-scheme: dark) {
:root {
color: red;
background-color: blue;
}
}Run Code Online (Sandbox Code Playgroud)
<body>
<button onClick="setPreferredColorScheme()">
toggle
</button>
</body>Run Code Online (Sandbox Code Playgroud)
以上是一个工作示例^
完整来源: https: //mybyways.com
我的答案基于此,但我已经包含了为了使其正常工作而必须进行的更改,此外我还添加了保留在本地存储中的功能。
重要的一点是它可以与@media (prefers-color-scheme: dark)CSS 一起使用,并且不需要为此工作而创建或复制额外的 CSS 类。换句话说,它适用于原生 CSS 配色方案。
在页面上我首先添加了一个太阳/月亮图标并将它们设置为不可见。
<a href="javascript:toggleColorScheme();">
<span id="icon-sun"></span>
<span id="icon-moon"></span>
</a>
<style>
#icon-sun {
width: 1.5rem;
height: 1.5rem;
display: none;
}
#icon-moon {
width: 1.5rem;
height: 1.5rem;
display: none;
}
</style>
Run Code Online (Sandbox Code Playgroud)
然后,这个 Javascript 完成了大部分工作。
// https://stackoverflow.com/questions/56300132/how-to-override-css-prefers-color-scheme-setting
// Return the system level color scheme, but if something's in local storage, return that
// Unless the system scheme matches the the stored scheme, in which case... remove from local storage
function getPreferredColorScheme(){
let systemScheme = 'light';
if(window.matchMedia('(prefers-color-scheme: dark)').matches){
systemScheme = 'dark';
}
let chosenScheme = systemScheme;
if(localStorage.getItem("scheme")){
chosenScheme = localStorage.getItem("scheme");
}
if(systemScheme === chosenScheme){
localStorage.removeItem("scheme");
}
return chosenScheme;
}
// Write chosen color scheme to local storage
// Unless the system scheme matches the the stored scheme, in which case... remove from local storage
function savePreferredColorScheme(scheme){
let systemScheme = 'light';
if(window.matchMedia('(prefers-color-scheme: dark)').matches){
systemScheme = 'dark';
}
if(systemScheme === scheme){
localStorage.removeItem("scheme");
}
else {
localStorage.setItem("scheme", scheme);
}
}
// Get the current scheme, and apply the opposite
function toggleColorScheme(){
let newScheme = "light";
let scheme = getPreferredColorScheme();
if (scheme === "light"){
newScheme = "dark";
}
applyPreferredColorScheme(newScheme);
savePreferredColorScheme(newScheme);
}
// Apply the chosen color scheme by traversing stylesheet rules, and applying a medium.
function applyPreferredColorScheme(scheme) {
for (var s = 0; s < document.styleSheets.length; s++) {
for (var i = 0; i < document.styleSheets[s].cssRules.length; i++) {
rule = document.styleSheets[s].cssRules[i];
if (rule && rule.media && rule.media.mediaText.includes("prefers-color-scheme")) {
switch (scheme) {
case "light":
rule.media.appendMedium("original-prefers-color-scheme");
if (rule.media.mediaText.includes("light")) rule.media.deleteMedium("(prefers-color-scheme: light)");
if (rule.media.mediaText.includes("dark")) rule.media.deleteMedium("(prefers-color-scheme: dark)");
break;
case "dark":
rule.media.appendMedium("(prefers-color-scheme: light)");
rule.media.appendMedium("(prefers-color-scheme: dark)");
if (rule.media.mediaText.includes("original")) rule.media.deleteMedium("original-prefers-color-scheme");
break;
default:
rule.media.appendMedium("(prefers-color-scheme: dark)");
if (rule.media.mediaText.includes("light")) rule.media.deleteMedium("(prefers-color-scheme: light)");
if (rule.media.mediaText.includes("original")) rule.media.deleteMedium("original-prefers-color-scheme");
break;
}
}
}
}
// Change the toggle button to be the opposite of the current scheme
if (scheme === "dark") {
document.getElementById("icon-sun").style.display = 'inline';
document.getElementById("icon-moon").style.display = 'none';
} else {
document.getElementById("icon-moon").style.display = 'inline';
document.getElementById("icon-sun").style.display = 'none';
}
}
applyPreferredColorScheme(getPreferredColorScheme());
Run Code Online (Sandbox Code Playgroud)
因此,在页面加载时,该applyPreferredColorScheme(getPreferredColorScheme())方法将运行,它会检查系统和本地存储并找出要应用的主题。它还根据当前主题在太阳或月亮图标之间切换。
当用户单击图标来切换主题时,toggleColorScheme()运行会将所选主题存储在本地存储中,但有一点不同 - 如果用户切换回与其操作系统匹配的主题,代码只会从本地存储中删除该项目。尝试尽可能保持原生。
JSFiddle:https://jsfiddle.net/35e0a97a/xmt1k659/78/
I have determined an appropriate solution, it is as follows:
CSS will use variables and themes:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
The variables are then called where necessary, for example:
//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);
}
Run Code Online (Sandbox Code Playgroud)
JavaScript is used to identify which theme the user has set, or if they have over-ridden their OS theme, as well as to toggle between the two, this is included in the header prior to the output of the 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();
Run Code Online (Sandbox Code Playgroud)
This javascript is used to toggle between the settings, it does not need to be included in the header of the page, but can be included wherever
//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;
}
Run Code Online (Sandbox Code Playgroud)
finally, the HTML checkbox to toggle between themes:
<label id="theme-switch" class="theme-switch" for="checkbox_theme">
<input type="checkbox" id="checkbox_theme">
</label>
Run Code Online (Sandbox Code Playgroud)
Through the use of CSS variables and JavaScript, we can automatically determine the users theme, apply it, and allow the user to over-ride it as well. [As of the current time of writing this (2019/06/10), only Firefox and Safari support the automatic theme detection]
这是一个尊重默认值的答案prefers-color-scheme,只有这样您才能通过 进行切换localStorage。这假设 CSS 比 JS 执行得更快,而且即使没有 JS,人们也会使用默认方案。
我不喜欢必须声明一个默认样式,然后将其重新声明为一个独立的类,但这是不可避免的。我至少曾经:root避免重复的值。
请注意,该论坛似乎已被屏蔽localStorage,因此您必须在其他地方尝试该代码。
var theme, prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
if (prefersDarkScheme.matches)
theme = document.body.classList.contains("light-mode") ? "light" : "dark";
else
theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
localStorage.setItem("theme", theme);
function toggle() {
var currentTheme = localStorage.getItem("theme");
if (currentTheme == "dark")
document.body.classList.toggle("light-mode");
else if (currentTheme == "light")
document.body.classList.toggle("dark-mode");
}Run Code Online (Sandbox Code Playgroud)
:root {
--text-for-light: black;
--bkg-for-light: white;
--link-for-light: green;
--text-for-dark: white;
--bkg-for-dark: black;
--link-for-dark: DeepSkyBlue;
}
body {color: var(--text-for-light); background-color: var(--bkg-for-light);}
a {color: var(--link-for-light);}
.dark-mode {color: var(--text-for-dark); background-color: var(--bkg-for-dark);}
.dark-mode a {color: var(--link-for-dark);}
.light-mode {color: var(--text-for-light); background-color: var(--bkg-for-light);}
.light-mode a {color: var(--link-for-light);}
@media (prefers-color-scheme: dark) {
body {color: var(--text-for-dark); background-color: var(--bkg-for-dark);}
a {color: var(--link-for-dark);}
}Run Code Online (Sandbox Code Playgroud)
<button onclick="toggle()">Toggle Light/Dark Mode</button>
<p> </p>
Test <a href="link">link</a>Run Code Online (Sandbox Code Playgroud)
如果您只想要自动检测部分而不需要切换按钮:
:root {
--text-for-light: black;
--bkg-for-light: white;
--link-for-light: green;
--text-for-dark: white;
--bkg-for-dark: black;
--link-for-dark: DeepSkyBlue;
}
body {color: var(--text-for-light); background-color: var(--bkg-for-light);}
a {color: var(--link-for-light);}
@media (prefers-color-scheme: dark) {
body {color: var(--text-for-dark); background-color: var(--bkg-for-dark);}
a {color: var(--link-for-dark);}
}Run Code Online (Sandbox Code Playgroud)
Test <a href="link">link</a>Run Code Online (Sandbox Code Playgroud)
您可以使用我<dark-mode-toggle>最初遵循用户prefers-color-scheme设置的自定义元素,但这也允许用户(永久或临时)覆盖它。切换适用于单独的 CSS 文件或切换的类。该自述有两种方法的例子。
index.html<!DOCTYPE html>
<html>
<head>
<meta name="color-scheme" content="light dark">
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<h1>Hello world</h1>
<button id="toggle">Toggle</button>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
style.css.dark-mode {
background-color: black;
color: white;
}
.light-mode {
background-color: white;
color: black;
}
@media (prefers-color-scheme: dark) {
body {
background-color: black;
color: white;
}
}
Run Code Online (Sandbox Code Playgroud)
script.js/**
* Adopt:
* the theme from the system preferences; or
* the previously stored mode from the `localStorage`
*/
var initialMode = "light";
var prefersColorSchemeDark = window.matchMedia( "(prefers-color-scheme: dark)" );
if ( prefersColorSchemeDark.matches ) {
initialMode = "dark";
}
if( localStorage.getItem("initialMode") == null ) {
localStorage.setItem("initialMode", initialMode);
}
if( localStorage.getItem("currentMode") == null ) {
localStorage.setItem("currentMode", initialMode);
} else {
let currentMode = localStorage.getItem("currentMode");
if ( currentMode == "dark" && currentMode != initialMode ) {
document.body.classList.add("dark-mode");
} else if ( currentMode == "light" && currentMode != initialMode ) {
document.body.classList.add("light-mode");
}
}
/**
* Process the toggle then store to `localStorage`
*/
document.getElementById('toggle').addEventListener("click", function() {
var initialMode = localStorage.getItem("initialMode");
let currentMode = localStorage.getItem("currentMode");
if ( currentMode == "dark" && currentMode == initialMode ) {
document.body.classList.add("light-mode");
localStorage.setItem("currentMode", "light");
} else if ( currentMode == "light" && currentMode == initialMode ) {
document.body.classList.add("dark-mode");
localStorage.setItem("currentMode", "dark");
} else if ( currentMode != initialMode ) {
document.body.removeAttribute("class");
if( currentMode == "dark" ) {
localStorage.setItem("currentMode", "light");
} else {
localStorage.setItem("currentMode", "dark");
}
}
},
false);
Run Code Online (Sandbox Code Playgroud)
该解决方案假设:
该解决方案松散地基于此解决方案/sf/answers/5258733231/,但实际上功能正常(此人没有考虑诸如 之类的情况@media (prefers-color-scheme: light) {})。
/*
JS file for managing light / dark themes
The toggle_theme(); function toggles the saved theme and updates the screen accordingly
The remove_theme(); function removes the theme from localstorage and only updates the screen if it doesn't match the system settings
The window.matchMedia(); function call watches for updates to system settings to keep localstorage settings accurate
*/
function get_system_theme() {
/*
Function for getting the system color scheme
*/
theme = "dark";
if (window.matchMedia("(prefers-color-scheme: light)").matches) {
theme = "light";
}
return theme;
}
function toggle_saved_theme() {
/*
Function for toggling between the two themes saved to local storage
Returns:
Value stored in local storage
*/
// Gets Current Value
if (localStorage.getItem("theme")) {
theme = localStorage.getItem("theme");
}
else {
theme = get_system_theme();
}
// Sets the stored value as the opposite
if (theme === "light") {
localStorage.setItem("theme", "dark");
}
else {
localStorage.setItem("theme", "light");
}
return localStorage.getItem("theme");
}
function switch_theme_rules() {
/*
Function for switching the rules for perfers-color-scheme
Goes through each style sheet file, then each rule within each stylesheet
and looks for any rules that require a prefered colorscheme,
if it finds one that requires light theme then it makes it require dark theme / vise
versa. The idea is that it will feel as though the themes switched even if they haven't.
*/
for (var sheet_file = 0; sheet_file < document.styleSheets.length; sheet_file++) {
try {
for (var sheet_rule = 0; sheet_rule < document.styleSheets[sheet_file].cssRules.length; sheet_rule++) {
rule = document.styleSheets[sheet_file].cssRules[sheet_rule];
if (rule && rule.media && rule.media.mediaText.includes("prefers-color-scheme")) {
rule_media = rule.media.mediaText;
if (rule_media.includes("light")) {
new_rule_media = rule_media.replace("light", "dark");
}
if (rule_media.includes("dark")) {
new_rule_media = rule_media.replace("dark", "light");
}
rule.media.deleteMedium(rule_media);
rule.media.appendMedium(new_rule_media);
}
}
}
catch (e) {
broken_sheet = document.styleSheets[sheet_file].href;
console.warn(broken_sheet + " broke something with theme toggle : " + e);
}
}
}
function toggle_theme() {
/*
Toggles the current theme used
*/
stored_theme = toggle_saved_theme();
switch_theme_rules();
}
function remove_theme() {
/*
Function for removing theme from local storage
*/
if (localStorage.getItem("theme")) {
if (get_system_theme() != localStorage.getItem("theme")) {
switch_theme_rules();
}
localStorage.removeItem("theme");
}
}
window.matchMedia('(prefers-color-scheme: dark)')
/*
This makes it such that if a user changes the theme on their
browser and they have a preferred theme, the page maintains its prefered theme.
*/
.addEventListener("change", event => {
if (localStorage.getItem("theme")) {
switch_theme_rules(); // Switches Theme every time the prefered color gets updated
}
}
)
if (localStorage.getItem("theme")) {
if (get_system_theme() != localStorage.getItem("theme")) {
switch_theme_rules();
}
}Run Code Online (Sandbox Code Playgroud)
:root {
--main-background: white;
--text-color: black;
}
@media screen and (prefers-color-scheme: dark) {
:root {
--main-background: black;
--text-color: white;
}
}
body {
background-color: var(--main-background);
}
* {
color: var(--text-color);
}Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html lang="en">
<body>
<p>Some Text</p>
<button onclick="toggle_theme();">Change Theme!</button>
<button onclick="remove_theme();">Remove Theme!</button>
</body>
</html>Run Code Online (Sandbox Code Playgroud)
希望这对那里的人有帮助!