基于Web组件,手把手教你搭建黑暗主题

我们绕了一圈后,又回到了黑暗模式。从黑暗模式到浅色模式,绕了一大圈然后又回到了黑暗模式。在个人电脑时代的早期,黑暗模式是唯一的选择。单色CRT计算机显示器的工作原理是将电子束发射到荧光屏上。早期CRT中使用的荧光粉是绿色的,导致文本显示为绿色,而屏幕的其余部分显示为黑色。这些模式通常被称为绿色屏幕

图片来自wikimedia

随着后来彩色CRT的引入,显示器通过使用红、绿、蓝三色荧光粉可以显示多种颜色。白色是通过同时激活所有三种荧光粉而产生的。现在我们又回到了黑暗主题,因为它让人的眼睛更舒服,并且从主观审美上让人更愉悦。

我非常喜欢web组件,它们让web开发变成了面向组件开发的方式,我很喜欢这种方式。下面就让我们仅使用web组件构建一个切换黑暗和浅色主题的小程序。

“面向组件的编程将是未来的趋势。"——Indrek Lasn

Web组件是许多不同技术的组合,它允许您创建可重用的自定义元素(其封装的功能可与您的其他代码隔离开来),并在web应用程序中使用这些元素。如果您不太了解web组件是什么,请查看“Web组件的概要”。

开始

我们只需要一个web浏览器和一个文本编辑器就够了。然后创建index.html文件。如果您正在使用emmet,您可以直接输入!,然后点击tab键。这将为您显示出index.html的样例代码。

<!DOCTYPE html>
	<html lang="en">
	<head>
	  <meta charset="UTF-8">
	  <meta name="viewport" content="width=device-width, initial-scale=1.0">
	  <meta http-equiv="X-UA-Compatible" content="ie=edge">
	  <title>Toggle</title>
	</head>
	<body>
	  
	</body>
	</html>

元素

多亏了开源代码,我们已经有了一个方便的组件来满足我们的需求。它被称为dark-mode-toggle——我们可以通过CDN包含该组件,或者将之视为NPM软件包安装。

以下组件是一个自定义元素,使您可以轻松地将一个黑暗模式切换开关放在您的网站上,您一开始可以使用prefers-color-scheme读取用户设置的偏好,但也允许用户选择性地只在这个网页上覆盖系统设置,并且这种单独设置可以是永久生效的。

被称为prefers-color-scheme的媒体特性用于检测用户的页面请求所要求的是浅色主题还是黑暗主题。它有以下三个值。

  • no-preference:表示用户没有向浏览器显示任何首选项。此关键字值在布尔上下文中计算为false。
  • light:表示用户已经告知浏览器,他们更喜欢浅色主题的页面(浅色背景上的深色文本)。
  • dark:表示用户已经告知浏览器,他们更喜欢黑暗主题的页面(深色背景上的浅色文本)。

将以下代码放到index.html的部分:

<!DOCTYPE html>
	<html lang="en">
	    <head>
	      <link rel="stylesheet" href="common.css" />
	      <link
	        rel="stylesheet"
	        href="light.css"
	        media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
	      />
	      <link
	        rel="stylesheet"
	        href="dark.css"
	        media="(prefers-color-scheme: dark)"
	      />
	      <script
	        type="module"
	        src="https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs"
	      ></script>
	


	      <meta charset="UTF-8" />
	      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
	      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
	      <title>Toggle</title>
	    </head>
	  <body>
	  </body>
	</html>

自定义元素假设您已经将CSS组织到不同的文件中,浏览器会根据样式表相应的link元素中的media属性有条件地加载这些文件。以下样式表被命名为common.css、light.css和dark.css——注意每个主题是怎样具有自己的封装样式的。继续创建这三个样式表。

touch common.css light.css dark.css

这是一个很好的高性能模式,因为浏览器会遵循人们当前的主题偏好,而不会强制人们下载他们不需要的CSS,虽然不匹配的样式表仍然会被加载,但是不会在关键的渲染通道上争夺带宽资源。

接下来,将元素添加到index.html中。

<aside>
	  <dark-mode-toggle
	    id="dark-mode-toggle"
	    legend="Theme Switcher"
	    light="Light"
	    dark="Dark"
	    appearance="switch"
	    permanent="false"
	  ></dark-mode-toggle>
	</aside>

添加dark-mode-toggle元素 到了这一步,我们还应该添加一些内容。毕竟,我们想要看到并测试我们的结果。下面是我们现在的index.html文件的样子:

<!DOCTYPE html>
	<html lang="en">
	  <head>
	    <link rel="stylesheet" href="common.css" />
	    <link
	      rel="stylesheet"
	      href="light.css"
	      media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
	    />
	    <link
	      rel="stylesheet"
	      href="dark.css"
	      media="(prefers-color-scheme: dark)"
	    />
	    <script
	      type="module"
	      src="https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs"
	    ></script>
	


	    <meta charset="UTF-8" />
	    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
	    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
	    <title>Toggle</title>
	  </head>
	  <body>
	    <aside>
	      <dark-mode-toggle
	        id="dark-mode-toggle"
	        legend="Theme Switcher"
	        light="Light"
	        dark="Dark"
	        appearance="switch"
	        permanent="false"
	      ></dark-mode-toggle>
	    </aside>
	


	    <main>
	      <h1>Hi there!</h1>
	      <p>
	        Lorem ipsum dolor sit amet, legere ancillae ne vis. Ne vim laudem
	        accusam consectetuer, eu utinam integre abhorreant sea. Quo eius veri
	        ei.
	      </p>
	      <form id="content">
	        <fieldset>
	          <legend>Lorem ipsum</legend>
	          <div>
	            <select>
	              <option>Lorem</option>
	              <option>Ipsum</option>
	            </select>
	          </div>
	          <div>
	            <button type="button">Lorem</button>
	          </div>
	          <div>
	            <input type="text" value="Lorem ipsum" />
	          </div>
	          <div>
	            <input type="search" value="Lorem ipsum" />
	          </div>
	          <div>
	            <label><input checked type="checkbox" /> Lorem</label>
	            <label><input type="checkbox" /> Ipsum</label>
	          </div>
	          <div>
	            <label><input checked name="foo" type="radio" /> Lorem</label>
	            <label><input name="foo" type="radio" /> Ipsum</label>
	          </div>
	        </fieldset>
	      </form>
	    </main>
	  </body>
	</html>

最后,我们需要声明黑暗和浅色主题的样式。请从下面的代码片段中获取样式。

common.css

这些样式在黑暗和浅色主题之间可以复用。

:root {
	  color-scheme: dark light; /* stylelint-disable-line property-no-unknown */
	  --heading-color: red;
	  --duration: 0.5s;
	  --timing: ease;
	}
	


	*,
	::before,
	::after {
	  box-sizing: border-box;
	}
	


	body {
	  margin: 0;
	  transition: color var(--duration) var(--timing),
	    background-color var(--duration) var(--timing);
	  font-family: sans-serif;
	  font-size: 12pt;
	  background-color: var(--background-color);
	  color: var(--text-color);
	  display: flex;
	  justify-content: center;
	}
	


	main {
	  margin: 1rem;
	  max-width: 30rem;
	  position: relative;
	}
	


	h1 {
	  color: var(--heading-color);
	  text-shadow: 0.1rem 0.1rem 0.1rem var(--shadow-color);
	  transition: text-shadow var(--duration) var(--timing);
	}
	


	img {
	  max-width: 100%;
	  height: auto;
	  transition: filter var(--duration) var(--timing);
	}
	


	p {
	  line-height: 1.5;
	  word-wrap: break-word;
	  overflow-wrap: break-word;
	  hyphens: auto;
	}
	


	fieldset {
	  border: solid 0.1rem;
	  box-shadow: 0.1rem 0.1rem 0.1rem var(--shadow-color);
	  transition: box-shadow var(--duration) var(--timing);
	}
	


	div {
	  padding: 0.5rem;
	}
	


	aside {
	  position: absolute;
	  right: 0;
	  padding: 0.5rem;
	}
	


	aside:nth-of-type(1) {
	  top: 0;
	}
	


	aside:nth-of-type(2) {
	  top: 3rem;
	}
	


	aside:nth-of-type(3) {
	  top: 7rem;
	}
	


	aside:nth-of-type(4) {
	  top: 12rem;
	}
	


	#content select,
	#content button,
	#content input[type="text"],
	#content input[type="search"] {
	  width: 15rem;
	}
	


	dark-mode-toggle {
	  --dark-mode-toggle-remember-font: 0.75rem "Helvetica";
	  --dark-mode-toggle-legend-font: bold 0.85rem "Helvetica";
	  --dark-mode-toggle-label-font: 0.85rem "Helvetica";
	  --dark-mode-toggle-color: var(--text-color);
	  --dark-mode-toggle-background-color: none;
	


	  margin-bottom: 1.5rem;
	}
	


	#dark-mode-toggle {
	  --dark-mode-toggle-dark-icon: url("moon.png");
	  --dark-mode-toggle-light-icon: url("sun.png");
	  --dark-mode-toggle-icon-size: 1rem;
	  --dark-mode-toggle-icon-filter: invert(100%);
	}

注意color-scheme属性。color-scheme属性仍在开发中,可能还没有得到完全支持。Chrome将在2019年底对其提供全面支持。

dark.css

这些是我们黑暗主题的样式。

:root {
	  --background-color: rgb(40, 44, 53);
	  --text-color: rgb(240, 240, 240);
	}
	


	.icon {
	  filter: invert(100%);
	}
	


	/* 如果不存在黑暗模式用户agent,那就模拟它 */
	select,
	input,
	button,
	option {
	  color: var(--text-color);
	  background-color: var(--background-color);
	  border-width: 1px;
	  border-radius: 1px;
	}
	


	/* Else, use the user agent stylesheet */
	@media (prefers-color-scheme: dark) {
	  select,
	  input,
	  button,
	  option {
	    color: unset;
	    background-color: unset;
	  }
	}

dark.css

light.css

最后是浅色主题的样式。

:root {
	  --background-color: rgb(240, 240, 240);
	  --text-color: rgb(15, 15, 15);
	}

在浏览器中打开index.html文件。您可以在本地打开它,也可以启动一个现成的HTTP服务器。在我的例子中,我将使用内置的Python服务器来打开它。

$ python -m SimpleHTTPServer

启动我们的Python服务器

现在,如果我们打开浏览器并输入localhost:8000——我们应该会看到以下内容:

继续点击右上角的主题切换按钮。

太酷了!这招很管用。您可以在GitHub代码库中找到所有的图片资源。

如果您是JavaScript新手,而且想要学习这门语言,我建议您从阅读书籍开始,边学边构建代码。从“学习JavaScript的更聪明方法”这本书开始,这里有一个有趣的应用程序列表

谢谢您的阅读,我希望您学到了一些东西。继续加油!

原文链接:

How to Build Light and Dark Themes With Web Components

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/IjRSmCEO5NFBoOKYRXCE

扫码关注云+社区

领取腾讯云代金券