CCSS自定义属性怎样实现主题切换?

在本教程中,我们将使用 CSS自定义属性(也称为CSS变量)来为简单的HTML页面实现主题切换。 我们将创建暗黑和明亮的示例主题,然后编写JavaScript 以在用户单击按钮时在两者之间切换。

就像在典型的编程语言中一样,变量用于保存或存储值。 在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页面

让我们从为项目创建一个文件夹开始:

BASH 代码:

$ mkdir css-variables-theming

接下来,在项目的文件夹中添加一个 index.html 文件:

BASH 代码:

$ cd css-variables-theming$ touch index.html

并添加以下内容:

HTML 代码:

Title

 
     
   

What is Lorem Ipsum?

   

Lorem Ipsum is simply dummy text of the printing and typesetting industry...

  Copyright 2018

我们使用 <nav> 标签添加一个导航栏,页脚和容器 <div> ,容器中包含一个按钮(用于在明暗主题之间切换)和一些虚拟 Lorem Ipsum 文本。

为我们的HTML页面编写基本CSS

现在让我们为页面添加样式。在 <head> 中使用内联 <style> 标记的同一文件中添加以下CSS样式:

HTML 代码:

* {  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%);  padding: 1rem;}p.content{  padding: 0.7rem;  font-size: 0.7rem;  color: hsl(350, 50%, 50%);}.container h2.title{  padding: 1rem;  color: hsl(350, 50%, 20%);}footer{  background: hsl(350, 93%, 88%);  padding: 1rem;}input[type=button] {  color:hsl(350, 50%, 20%);  padding: 0.3rem;  font-size: 1rem;}

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 的值,我们可以为用户提供许多彩色主题的可能性。

以下代码行将 --main-hue 的值设置为240(蓝色):

JavaScript 代码:

document.documentElement.style.setProperty('--main-hue', 240);

查看以下 CodePen ,其显示了一个完整示例,允许您在红色,蓝色和绿色之间动态切换主题:

他是页面的截图:

添加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 代码:

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)以创建浅色主题的暗色版本。

来源:https://www.sitepoint.com/css-theming-custom-properties-javascript/

如果您在web学习的过程中遇到难题,欢迎关注微信公众号【筑梦前端】,大家一起交流解决!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容