Web上的黑暗模式完整指南

2020-07-05 04:25:51

暗模式最近获得了很大的吸引力。例如,像苹果一样,在其iOS和MacOS操作系统中增加了黑暗模式。Windows和谷歌也做了同样的事情。

让我们进入网站背景下的黑暗模式。我们将深入研究实现暗模式设计的不同选项和方法,以及它们所涉及的技术考虑因素。在此过程中,我们还将介绍一些设计技巧。

典型的情况是,您的站点已经有了一个浅色的主题,并且您感兴趣的是制作一个较暗的对应物。或者,即使你是从零开始,你也会有两个主题:光明和黑暗。一个主题应该被定义为用户第一次访问时获得的默认主题,这在大多数情况下都是较轻的主题(尽管我们可以让用户的浏览器为我们做出选择,正如我们将看到的那样)。还应该有一种切换到其他主题的方法(这可以自动完成,正如我们将看到的)-就像在中一样,用户单击一个按钮,颜色主题就会改变。

这里的诀窍是换出一个类,该类可以作为钩子在页面上的任何位置更改样式。

下面是用于切换该类的按钮的脚本,例如:

//选择Buttonconst btn=document.querySelector(';.btn-toggle';);//侦听单击按钮btn.addEventListener(';单击';,Function(){//然后将.Dark-Theme类切换(添加/删除)到Body document.body.classList.toggle(';dark-theme';);})。

<;BODY>;BUTTOGLE class=";BTN-TOGGLEG";>;切换深色模式<;/Button>;BODY>;h1>;嗨!这只是一个标题<;/h2>;p>;我只是一个枯燥的文本,在这里存在完全是为了演示<;/p<;p>;,我只是另一个和我上面的人一样的人,因为两个比只有一个<;/p<;p<;a href=";#&34;>;我是一个链接,

这种方法的总体思路是像我们通常所说的那样设置样式,将其称为我们的“默认”颜色模式,然后使用在“<;Body>;”元素上设置的一个类来创建一套完整的颜色样式,我们可以将其用作另一个“暗”颜色模式。

假设我们的默认值是浅色方案。所有这些“轻”样式的编写方式与您通常编写CSS的方式完全相同。给定HTML,让我们对正文和链接应用一些全局样式。

很好。我们有深色文字(#222)和深色链接(#0033cc),背景是浅色(#FFF),我们最新的“默认”主题有了一个坚实的开端。

现在,让我们重新定义这些属性值,这次是在不同的Body类上设置的:

BODY{color:#222;a背景:#fff;}a{color:#0033cc;}
/*深色模式样式*/body.Dark-主题{x颜色:#eee;b背景:#121212;}Body.Dardy.Dark-主题a{7color:#809fff;}。

深色主题样式将是同一父类的后代-在本例中是.Dark-Theme-我们已经将其应用于t<;body>;标签。(=。

我们怎么才能“切换”身体类来访问黑暗风格呢?我们可以使用JavaScript!我们将选择按钮类BUTTOGLE(.btn-toglger),并在单击按钮时添加侦听器,然后将黑色主题类BUTY(.Dark-Theme)添加到Body元素的类列表中。由于层叠和专一性,这有效地覆盖了我们设置的所有“浅”的颜色。

以下是正在运行的完整代码。单击切换按钮可切换进入和退出黑暗模式。

我们可以在每个主题的样式表之间切换,而不是将所有样式放在一个样式表中。这里假设您已经准备好了完整的样式表。

然后,我们可以为黑暗主题创建样式,并将它们保存在一个单独的样式表中,我们称之为Dark-Theme.css。

这为我们提供了两个独立的样式表,每个主题都有一个样式表,我们可以在HTML标题>;的部分中链接起来。让我们首先链接灯光样式,因为我们将其称为默认样式。

<;!DOCTYPE html>;<;html lang=";en";>;<;Head>;id=";theme-link";>;<;/head>;
<;!--<;!--轻型主题样式表-->;
<;link href=";light-heme.css";rel=";样式表";样式表";HTML等-->;
<;/HTML>。

我们使用的是一个#主题链接ID,我们可以用JavaScript选择它,再次在亮模式和暗模式之间切换。只是这一次,我们切换的是文件而不是类。

//选择按钮const btn=document.querySelector(";.btn-toggle";);//选择样式表<;链接>;const Theme=document.querySelector(";#theme-link";);//聆听单击按钮btn.addEventListener(";click";,function(){//如果当前url包含";ligh-heme.css";if(heme.getAttribute(";href";)==";Light-Theme.css";){//.。然后将其切换为";Dark-heme.css";heme.href=";Dark-heme.css";;//否则.。}其他{//.。切换到";light-heme.css";heme.href=";light-heme.css";;}});

我们还可以利用CSS的自定义属性的力量来创建黑色主题!它帮助我们避免为每个主题编写单独的样式规则集,从而使编写样式的速度更快,如果需要的话,对主题进行更改也容易得多。

我们仍然可以选择交换Body类,然后使用该类重新设置自定义属性:

//选择Buttonconst btn=document.querySelector(";.btn-toggle";);
//侦听单击按钮btn.addEventListener(";单击";,Function(){document.body.classList.toggle(";dark-theme";);});//然后将.Dark-Theme类切换(添加/删除)到正文:btn.addEventListener

首先,让我们将默认灯光颜色值定义为Body元素上的自定义属性:

现在,我们可以像在第一个方法中所做的那样,在一个.Dark主题的Body类上重新定义这些值:

我们也可以在document:root中定义我们的自定义属性。这完全是合法的,甚至是普遍的做法。在这种情况下,所有默认主题样式定义都将放入:root{},所有暗主题属性将放入:root.Dark-mode{}。

如果我们已经在使用服务器端语言,比如PHP,那么我们可以使用它来代替JavaScript。如果您更喜欢直接在标记中工作,这是一个很好的方法。

<;?php$ThemeClass=';';;if(isset($_GET($_Get[';Theme';])&;&&Get[';Theme';]==';Dark';){$ThemeClass=';Dark-Theme&39;}
$ThemeToggler=($ThemeClass==';Dark-Theme&39;)?<;!DOCTYPE html>;<;html lang=";EN";>;<;!--等-->;<;Body class=";?<;?PHP ECHO$ThemeClass;?>;<;a href=";?Theme=<;?PHP ECHO$theeTogger;?>;/body>;<;/html>;

我们可以让用户发送GET或POST请求。然后,当页面重新加载时,我们让我们的代码(在本例中为PHP)应用于适当的主体类。出于本演示的目的,我使用GET请求(URL参数)。

<;?php$ThemeStyleSheet=';light-heme.css';if(isset($_GET($_GET[##39;Theme';])&;&$_Get[';Theme';]==';Dark';){$ThemeStyleSheet=';Dark-Theme.css';}
$ThemeToggler=($Theme。Dark';?>;<;!DOCTYPE html>;<;html lang=";en";>;<;head<;!--等-->;rel=";stylesheet";>;<;/head>;
<;body>;;link href=";<;?php ECHO$theeStyleSheet;?>;a HREF。?PHP ECHO$heme切换;?>;&34;>;切换黑暗模式<;/a>;!--等-->;<;/body>;<;/html>;

这种方法有一个明显的缺点:需要刷新页面才能进行切换。但是,像这样的服务器端解决方案对于在页面重新加载时持久化用户的主题选择很有用,我们稍后将会看到这一点。

“正确”的方法归根结底取决于您项目的要求。例如,如果您正在做一个大型项目,您可以使用CSS属性来帮助处理大型代码库。另一方面,如果您的项目需要支持传统浏览器,则需要使用另一种方法。

此外,并没有说我们只能使用一种方法。有时,多种方法的结合将是最有效的途径。除了我们已经讨论过的方法之外,甚至可能还有其他可能的方法。

到目前为止,我们已经使用一个按钮在亮模式和暗模式之间切换,但我们可以简单地让用户的操作系统为我们完成这一操作。例如,许多操作系统允许用户在系统设置中直接在亮和暗主题之间进行选择。

幸运的是,CSS有一个更偏爱的配色方案和媒体查询,可以用来检测用户的系统配色方案偏好。它可以有三个可能的值:没有偏爱,没有光,没有暗。在MDN上阅读更多关于它的信息。

@MEDIA(首选配色方案:深色){
/*此处显示深色主题样式*/}MEDIA(首选配色方案:浅色){/*此处显示浅色主题样式*/}。

@MEDIA(首选配色方案:深色){正文{color:#eee;背景:#121212;}
:a{color:#809fff;}}。

现在,如果用户在系统设置中启用了暗模式,那么默认情况下,他们将无法获得暗模式样式。我们不必求助于JavaScript或服务器端脚本来决定使用哪种模式。见鬼,我们甚至不再需要按钮了!

我们可以求助于JavaScript来检测用户的首选配色方案。这很像我们使用的第一种方法,只不过我们使用的是matchedMedia()来检测用户的偏好。

使用JavaScript有一个不利之处:当JavaScript在CSS之后执行时,可能会有一个轻量级主题的快速闪烁,这可能会被误解为bug。

当然,我们也可以像在第二种方法中那样交换样式表。这一次,我们将两个样式表链接起来,并使用媒体查询来确定应用了哪一个样式表。

我们刚刚了解了如何考虑用户的系统范围配色方案首选项。但是,如果用户想要覆盖他们对某个站点的系统首选项,该怎么办呢?仅仅因为用户更喜欢他们操作系统的黑暗模式并不总是意味着他们在网站上更喜欢黑暗模式。这就是为什么不管系统设置如何,提供一种手动覆盖暗模式的方法是一个好主意。

让我们使用CSS自定义属性方法来演示如何做到这一点。我们的想法是像以前一样定义两个主题的自定义属性,在Preferences-color-schema媒体查询中包装深色样式,然后在其中定义一个.light主题类,如果用户想要在这两种模式之间切换,我们可以使用它来覆盖深色模式属性。

/*默认颜色*/BODY{1--text-color:#222;1--bkg-color:#fff;}/*深色主题*/body.Dark-主题{1--text-color:#eee;2--bkg-color:#121212;}/*操作系统级别偏爱深色模式的用户使用的样式*/@MEDIA(首选配色方案:暗色){0/*默认为深色主题*/BODY{0--。*--bkg-color:#121212;}如果用户决定交换*/bkg-color:#121212;bkg-color:#fff;#}},则用亮模式样式覆盖深色模式。light-主题{1--text-color:#222;2--bkg-color:#fff;1}}。

现在,我们可以返回到值得信赖的按钮,在亮主题和暗主题之间切换。这样,我们在默认情况下尊重操作系统的颜色首选项,并允许用户手动切换主题。

//聆听按钮:btn.addEventListener(";单击";,Function(){//如果操作系统设置为暗模式.如果(Preferences sDarkScheme.Matches){//.),则应用.light-Theme类覆盖document.body.classList.toggle(";light-theme";);中的这些样式。((//否则.)其他{(/)//.应用.Dark-Theme类覆盖默认灯光样式(document.body.classList.toggle(";dark-theme";);(}}));

首选配色方案的媒体查询功能得到了主流浏览器的支持,包括Chrome 76+、Firefox 67+、Chrome Android 76+和Safari 12.5+(iOS上为13+)。它不支持IE和三星互联网浏览器。

这是一个很有希望的支持量!我可以使用估计用户覆盖率的80.85%吗?

目前支持暗模式的操作系统包括MacOS(Mojave或更高版本)、iOS(13.0+)、Windows(10+)和Android(10+)。

到目前为止,我们所看到的绝对像TIN中所说的那样:基于操作系统偏好或单击按钮来交换主题。这很好,但是当用户访问站点上的另一个页面或重新加载当前页面时,它不会继续存在。

我们需要保存用户的选择,以便在整个站点和后续访问中一致地应用它。为此,我们可以在切换主题时将用户的选择保存到localStorage。Cookie也非常适合这项工作。

我们有一个脚本,可以在切换发生时将所选主题保存到localStorage。换句话说,当页面重新加载时,脚本从localStorage获取选择并应用它。JavaScript通常在CSS之后执行,因此这种方法容易出现“主题错误的flash”(Foit)。

//选择按钮const btn=document.querySelector(";.btn-toggle";);//从localStorageconst currentTheme=localStorage.getItem(";Theme";);document.body.classList.add(";dark-theme";);中选择主题首选项;
//如果localStorage中的当前主题是";Dark&34;.if(currentTheme==";Dark";){0//.则使用.Dark-Theme类。}.addEventListener(";单击";,document.body.classList.toggle(";dark-theme";);(){
//每次单击函数时切换.Dark-Theme类)//让&/让';假设主题等于光,让Theme=";light";//如果正文包含.Dark-Theme类.如果(Document.body.classList.Concludes(";Dark-Theme";)){{#34;Theme";,.那么让我们将主题设为暗Theme=";Dark&34;;}//然后将选择保存在localStorage/localStorage.setItem(";Theme";,Theme);});

为了避免FLIC,我们可以使用服务器端脚本,如PHP。我们不会将用户的主题首选项保存在localStorage中,而是从JavaScript创建一个cookie并将其保存在那里。但是,这可能只有在您已经在使用服务器端语言的情况下才是可行的。

//选择按钮const btn=document.querySelector(";.btn-toggle";);
//聆听点击按钮:btn.addEventListener(";click";,function(){document.body.classList.toggle(";dark-theme";);//切换Body上的.Dark-Theme类://让';让我们说主题等于光,让Theme=";light";(//如果正文包含.Dark-Theme类.如果(document.body.classList.contains(";dark-theme";)){//.则让';让主题变暗(Theme=";Dark&34;;Theme})//然后将选择保存在Cookie文档中。Cookie=";Theme=";+Theme;});

现在,我们可以检查该cookie是否存在,并通过将适当的类应用于<;body>;标记来加载适当的主题。

<;?php$ThemeClass=';';如果(!Empty($_Cookie[';Theme';])&;&;$_Cookie[';Theme&39;]==';Dark&39;){$ThemeClass=';Dark-Theme&39;;}?>;
<;!DOCTYPE html&>。<;body class=";<;?PHP ECHO$theeClass;?>;&34;>;<;!--etc-->;<;/body>;<;/html>;

<;?php$hemeStyleSheet=';light-heme.css&39;if(!Empty($_cookie[';主题';])&;&;$_cookie[';主题&39;]=#39;暗&39;){$hemeStyleSheet=';暗主题.css';;}?>;
<。<;!--等-->;id=";theme-link";>;<;/head>;<;!--;link href=";<;?php echo$temeStyleSheet;?>;&34;rel=";样式表";LINK等-->;

如果你的网站有用户账户--比如登录和管理个人资料的地方--那也是保存主题偏好的好地方。将这些信息发送到存储用户帐户详细信息的数据库。然后,当用户登录时,从数据库获取主题,并使用PHP(或任何服务器端脚本)将其应用于页面。

有多种方法可以做到这一点。在本例中,我从数据库获取用户的主题首选项,并在登录时将其保存在会话变量中。

<;?php//登录操作if(!Empty($_POST[';LOGIN';]){
//等登录操作//如果用户已通过身份验证.*if($loginSuccess){//.。是否将其主题首选项保存到会话变量:$_SESSION[';USER_THEME';]=$userData[';THEME';];$}}
//如果设置了会话变量,则首先选择该变量;否则是否选择Cookie$ThemeChoice=$_SESSION[';USER_THEME';]??$_COOKIE[';THEME&39;]?NULL;$ThemeClass=';';IF($ThemeChoice==';Dark&39;){$ThemeClass=';Dark-Theme&39;;}?>;
<;!DOCTYPE html>;<;html lang=";en";>;<;!--等-->;<;Body class=&#。!--等-->;<;/body>;<;/html>;

我使用的是PHP的空合并运算符(??)。决定从何处选取主题首选项:从会话还是从Cookie。如果用户已登录,则采用会话变量的值,而不是cookie的值。如果用户未登录或已注销,则取cookie的值。

要通知浏览器UA样式表有关系统配色方案首选项的信息,并告诉它页面中支持哪些配色方案,我们可以使用配色方案元标记。

例如,假设页面应该同时支持“暗”和“亮”主题。我们可以将它们都作为值放在meta标记中,用空格分隔。如果我们只想支持“light”主题,那么我们只需要使用“light”作为值。这一点在CSSWG GitHub问题中进行了讨论,该问题最初是在CSSWG GitHub提出的。

添加此meta标记时,浏览器在呈现页面的UA控制的元素(如<;button>;)时会考虑用户的配色方案首选项。它根据用户的喜好呈现根背景、表单控件和拼写检查功能(以及任何其他UA控制的样式)的颜色。

虽然大部分主题都是手动设置样式的(这会覆盖UA样式),但通知浏览器受支持的主题有助于避免哪怕是最微小的潜在Foit情况。对于HTML已经呈现但CSS仍在等待加载的情况,情况就是如此。

在撰写本文时,配色方案属性缺乏广泛的浏览器支持,尽管Safari和Chrome都支持它。

//选择按钮const btn=document.querySelector(";.btn-toggle";);//在操作系统级别检查深色模式首选项const首选项DarkScheme=window.matchMedia(";(首选颜色方案:暗)";);
//如果用户';当前主题主题=localStorage.getItem(";主题&34;);//如果用户';主题首选项可用,则从本地存储获取用户的主题首选项(';ccurrentTheme=localStorage.getItem(";Theme";);Dark";){如果用户在本地存储中的首选项是document.body.classList.toggle(";dark-mode";);//,则让我们在Body和Document.classList上切换.Dark主题类;否则,如果(currentTheme==#34;light&34;){当前//.让我们在Body和Document.body.classList上切换.light-主题类(";){其他//.让我们切换Body和Document.classList上的.Dark-Theme类,否则(";)Else if(currentTheme==#34;light";){0//.让我们切换Body上的.light主题类。Light-mode";);}
//聆听点击按钮:addEventListener(";click";,Function(){0//如果用户的操作系统设置为黑色并且与我们的.DarkMode类匹配.如果(Preferences sDarkScheme.Matches){0//.),则在addEventListener中切换灯光模式类。btn.addEventListener(";Click";,Function(){btn.addEventListener(";,Function。*//.但如果.light-mode类已经在正文上,请使用.Dark-mode,var主题=document.body.classList.contains(";light-mode";)?";light&34;:";Dark&34;;document.body.classList.toggle(";dark-mode";);}否则,让我们做同样的事情,但对于.Dark-mode,请使用.Dark-mode。*var Theme=document.body.classList.contains(";dark-mode";)?";Dark";:";light";;n}//最后,让我们将当前首选项保存到localStorage以保留。

..