在本教程中,我们将使用 CSS 自定义属性(也称为 CSS 变量)来为简单的 HTML 页面实现主题切换。 我们将创建暗黑和明亮的示例主题,然后编写 JavaScript 以在用户单击按钮时在两者之间切换。
如果你以前没接触过,请先阅读 CSS 变量(自定义属性)实用指南及注意事项这篇文章
就像在典型的编程语言中一样,变量用于保存或存储值。 在 CSS 中,它们通常用于存储颜色,字体名称,字体大小,长度单位等。然后可以在样式表中的多个位置引用和重用它们。 大多数开发人员都会引用 “CSS 变量” ,但官方名称是 自定义属性。
CSS 自定义属性可以修改可在整个样式表中引用的变量。 以前,只有使用 Sass 等 CSS 预处理器才能实现这一点。
理解 root 和 var()
在创建动态主题示例之前,让我们了解自定义属性的基本基础知识。
自定义属性 是一个名称以两个连字符( - )开头的属性,如 --foo。 定义后可以使用 var() 引用的变量。 让我们考虑这个例子:
- //CSS 代码
- :root {
- --bg-color: #000;
- --text-color: #fff;
- }
在:root 选择器中定义自定义属性意味着它们可以作用于全局文档中所有元素。:root 是一个 CSS 伪类,它匹配文档的根元素 – <html>元素。它类似于 html 选择器,但具有更高的优先级。
您可以在文档中的任何位置访问 :root 中的自定义属性的值:
- //CSS 代码
- div {
- color: var(--text-color);
- background-color: var(--bg-color);
- }
您还可以在 CSS 变量中包含回退值。例如:
- //CSS 代码
- div {
- color: var(--text-color, #000);
- background-color: var(--bg-color, #fff);
- }
如果未定义自定义属性,则使用其回退值代替。
除了 :root 或 html 选择器之外的 CSS 选择器内定义的自定义属性使变量可用于匹配元素及其子元素。
CSS 自定义属性与预处理器变量
诸如 Sass 之类的 CSS 预处理器通常用于辅助前端 Web 开发。预处理器的其中一个有用功能就包括变量。但是 Sass 变量和 CSS 自定义属性之间有什么区别?
CSS 自定义属性在现代浏览器中进行本机解析。 预处理器变量需要编译到标准 CSS 文件中,并且所有变量都转换为值。
JavaScript 可以访问和修改自定义属性。 预处理程序变量编译一次,只有它们的最终值在客户端上可用。
编写 HTML 页面
让我们从为项目创建一个文件夹开始:
- //HTML 代码
- <nav class="navbar">Title</nav>
- <div class="container">
- <div>
- <input type="button" value="Light/Dark" id="toggle-theme" />
- </div>
- <h2 class="title">What is Lorem Ipsum?</h2>
- <p class="content">Lorem Ipsum is simply dummy text of the printing and typesetting industry...</p>
- </div>
- <footer>
- Copyright 2018
- </footer>
我们使用 <nav> 标签添加一个导航栏,页脚和容器 <div> ,容器中包含一个按钮(用于在明暗主题之间切换)和一些虚拟 Lorem Ipsum 文本。
编写基本 CSS
现在让我们为页面添加样式。在 <head> 中使用内联 <style> 标记的同一文件中添加以下 CSS 样式:
- <style>
- * {
- margin: 0;
- }
- html{
- height: 100%;
- }
- body{
- height: 100%;
- font-family: -apple-system, BlinkMacSystemFont“Segoe UI”, “Roboto”, “Oxygen”, “Ubuntu”, “Cantarell”,
- “Fira Sans”, “Droid Sans”, “Helvetica Neue”,sans-serif;
- display: flex;
- flex-direction: column;
- }
- nav{
- background: hsl(350, 50%, 50%);
- padding: 1.3rem;
- color: hsl(350, 50%, 10%);
- }
- .container{
- flex: 1;
- background:hsl(350, 50%, 95%);
CSS3 HSL(色调,饱和度,亮度)表示法用于定义颜色。 色调是色环上的角度,示例使用 350 表示红色。 通过更改饱和度(颜色百分比)和亮度(百分比),所有页面颜色都使用不同的变化。
使用 HSL,我们只需更改色调值,即可轻松尝试主题的不同主色。 我们还可以使用 CSS 变量作为色调值,并通过更改样式表中的单个值或使用 JavaScript 动态更改颜色主题来切换颜色主题。
我们将这个例子放到在线的 CodePen 中演示:
让我们使用 CSS 变量来保存页面中所有颜色的色调值。在 <style> 标记顶部的 :root 选择器中添加一个全局 CSS 变量:
- //CSS 代码
- :root{
- --main-hue : 350;
- }
接下来,我们用 -main-hue 变量替换 hsl() 颜色中的所有硬编码 350 值。例如,这是导航选择器:
- //CSS 代码
- nav{
- background: hsl(var(--main-hue) , 50%, 50%);
- padding: 1.3rem;
- color: hsl(var(--main-hue), 50%, 10%);
- }
现在,如果要指定除红色以外的其他颜色,则只需将相应的值指定给 --main-hue 即可。这里有一些例子:
- //CSS 代码
- :root{
- --red-hue: 360;
- --blue-hue: 240;
- --green-hue: 120;
- --main-hue : var(--red-hue);
- }
我们为红色,蓝色和绿色定义了三个自定义属性,然后将 --red-hue 变量分配给--main-hue。
这是一个屏幕截图,其中包含不同值的页面 --main-hue :
CSS 自定义属性提供了几个好处:
可以在单独位置定义值
可以适当地命名该值以帮助维护和可读性
可以使用 JavaScript 动态更改该值。 例如,--main-hue 可以设置为 0 到 360 之间的任何值
使用 JavaScript 从一组预定义值或用户提交的 hue 值(它应该在 0 到 360 之间)动态设置 --main-hue 的值,我们可以为用户提供许多彩色主题的可能性。
- //JavaScript 代码
- document.documentElement.style.setProperty('--main-hue', 240);
以上代码行将 --main-hue 的值设置为 240(蓝色):
他是页面的截图:
添加 CSS 暗黑主题
现在让我们为这个页面提供一个暗黑的主题。 为了更好地控制不同实体的颜色,我们需要添加更多变量。
通过页面的样式,我们可以在:root 中定义对应颜色的自定义属性后,用变量替换不同选择器中的所有 HSL 颜色:
- //CSS 代码
- :root{
- /*...*/
- --nav-bg-color: hsl(var(--main-hue) , 50%, 50%);
- --nav-text-color: hsl(var(--main-hue), 50%, 10%);
- --container-bg-color: hsl(var(--main-hue) , 50%, 95%);
- --content-text-color: hsl(var(--main-hue) , 50%, 50%);
- --title-color: hsl(var(--main-hue) , 50%, 20%);
- --footer-bg-color: hsl(var(--main-hue) , 93%, 88%);
- --button-text-color: hsl(var(--main-hue), 50%, 20%);
- }
使用了自定义属性的适当名称。 例如, --nav-bg-color 是指导航背景的颜色,而 --nav-text-color 是指导航前景/文本的颜色。
现在复制 :root 选择器及其内容,但添加一个暗黑属性值的主题:
- //CSS 代码
- :root[theme='dark']{
- /*...*/
- }
如果将具有 dark 值的 theme 属性添加到 <html> 元素,则会激活此主题。
我们现在可以手动插入这些变量的值,通过减少 HSL 颜色的亮度值来提供暗主题,或者我们可以使用其他技术,例如常用的 invert() 和 brightness() 等 CSS 滤镜调整图像的渲染,但也可以与任何其他元素一起使用。
将以下代码添加到 :root[theme='dark']:
- //CSS 代码
- :root[theme='dark'] {
- --red-hue: 360;
- --blue-hue: 240;
- --green-hue: 120;
- --main-hue: var(--blue-hue);
- --nav-bg-color: hsl(var(--main-hue), 50%, 90%);
- --nav-text-color: hsl(var(--main-hue), 50%, 10%);
- --container-bg-color: hsl(var(--main-hue), 50%, 95%);
- --content-text-color: hsl(var(--main-hue), 50%, 50%);
- --title-color: hsl(--main-hue, 50%, 20%);
- --footer-bg-color: hsl(var(--main-hue), 93%, 88%);
- --button-text-color: hsl(var(--main-hue), 50%, 20%);
- filter: invert(1) brightness(0.6);
- }
invert() 过滤器反转所选元素中的所有颜色(在这种情况下每个元素都会应用)。 可以用百分比或数字指定反转值。 值 100% 或 1 将完全反转元素的色调,饱和度和亮度值。
brightness() 滤镜使元素更亮或更暗。 值为 0 会导致完全黑色的元素。
invert() 滤镜使一些元素非常明亮。 通过设置 brightness(0.6) 来降低这些要求。
暗黑主题,不同程度的色调:
使用 JavaScript 切换主题
现在,当用户点击 Dark / Light 按钮时,我们现在使用 JavaScript 在暗黑和高亮主题之间切换。 在 index.html 中,使用以下代码在结束 </body> 之前添加内联 <script >:
- //JavaScript 代码
- const toggleBtn = document.querySelector("#toggle-theme");
- toggleBtn.addEventListener('click', e => {
- console.log("Switching theme");
- if(document.documentElement.hasAttribute('theme')){
- document.documentElement.removeAttribute('theme');
- }
- else{
- document.documentElement.setAttribute('theme', 'dark');
- }
- });
document.documentElement 引用文档的根 DOM 元素 – 即 <html> 元素。 此代码使用 .hasAttribute() 方法检查 theme 属性是否存在,如果该属性不存在则添加 dark 值,从而导致切换到暗黑主题。 否则,它会删除该属性,从而切换到高亮主题。
使用 JavaScript 更改 CSS 自定义属性
使用 JavaScript,我们可以访问自定义属性并动态更改其值。 在我们的示例中,我们对亮度值进行了硬编码,但它可以动态更改。 首先,在 Dark / Light 按钮旁边的 HTML 页面中添加 slider input:
- //HTML 代码
- <input type="range" id="darknessSlider" name="darkness" value="1" min="0.3" max="1" step="0.1" />
slider 从 1 开始,允许用户将其减小到 0.3 ,步长为 0.1 。
接下来,在:root[theme='dark']中为暗度值添加一个自定义属性,初始值为 1 :
- //CSS 代码
- :root[theme='dark']{
- /*...*/
- --theme-darkness: 1;
- }
将 brightness 滤镜更改为此自定义属性而不是硬编码值:
- //CSS 代码:
- filter: invert(1) brightness(var(--theme-darkness));
最后,添加以下代码以将 --theme-darkness 的值与 slider 值同步:
- //JavaScript 代码
- const darknessSlider = document.querySelector("#darknessSlider");
- darknessSlider.addEventListener('change', (e)=>{
- const val = darknessSlider.value
- document.documentElement.style.setProperty('--theme-darkness', val);
- });
我们正在监听滑块的 change 事件,并使用 setProperty() 方法相应地设置 --theme-darkness 的值。
我们还可以将 brightness 滤镜应用于高亮主题。 在 :root 选择器的顶部添加 --theme-darkness 自定义属性:
- //CSS 代码
- :root{
- /*...*/
- --theme-darkness: 1;
- }
然后在同一选择器的底部添加 brightness 滤镜:
- //CSS 代码
- :root{
- /*...*/
- filter: brightness(var(--theme-darkness));
- }
您可以在以下在线的 CodePen 中演示中找到此示例的完整代码:
这是最后一个例子的暗黑主题的截图:
这个是高亮主题的截图:
结论:
在本教程中,我们已经了解了如何使用 CSS 自定义属性来创建主题并在它们之间动态切换。 我们使用了 HSL 配色方案,它允许我们指定具有色调,饱和度和亮度值的颜色以及 CSS 滤镜(invert 和 brightness)以创建浅色主题的暗色版本。