动态调整系统主题色(4): CssVar 与 Variant 方案的探索

Image

动态调整系统主题色(4): CssVar 与 Variant 方案的探索

  • 动态调整系统主题色(4): CssVar 与 Variant 方案的探索
    • 前言
    • 方案的介绍与比较
      • CssVar (CSS 变量方案)
      • CSS 变量方案与 tailwindcss 的结合
      • Variant 方案
    • 2种方案在小程序上的示例
    • 之前的几篇

前言

这篇已经是动态调整系统主题色的第四篇了,转眼距离第一篇发布已经过去了2年的时间。随着时间的流逝,对技术的理解也在不断的进步,方案也在不断的完善和推陈出新,本篇文章就是在探讨系统主题色的 2 方案: CssVarVariant

方案的介绍与比较

假如你没有看前面三篇文章的话,初看到这 2 个词可能不能直观的知道它们是什么意思,下面我先简单介绍一下它们是什么以及它们的原理。

CssVar (CSS 变量方案)

这个方案很简单,大意就是我们预先定义出,有多少种颜色会被使用,贯穿整个设计规范。然后把它们定义成 CSS 变量,然后再通过更改 CSS 变量的值,去改变整个主题。

比如我们可以这样去定义:

:root{--prism-background: #f4f4f4;
}
/*暗色*/
html.dark{--prism-background: #181818;
}body{background-color: var(--prism-background);
}

这种方式把其他的主题定义在了 :root/html 选择器之下,本质上是在利用选择器的优先级去覆盖原先定义CSS变量的值,从而达到切换的效果。这个方案非常的通用,你看到的很多的组件库都是使用这个方案的,比如 element-plus / vant 等等,(antd 不是)

CSS变量会从它被使用的地方,从自己递归向上去寻找定义,所以我们想覆盖定义在 :root 里定义的变量,可以直接在它被使用到的地方再定义一个值,用来替换达到覆盖的效果。

所以,我们可以去封装一个组件 ThemeProvider,里面就定义一个 div 元素包裹一个插槽,再把CSS变量动态设置在这个元素上,从而达到切换插槽内局部CSS变量的效果。(是不是感觉似曾相识?)

CSS 变量方案与 tailwindcss 的结合

当然CSS变量方案和 tailwindcss 能够得到非常好的结合,我们只需要预先在tailwind.config.jstheme 中预先去扩展定义变量即可。

不过和上面那种方式有些不同,这里我们定义的 CSS 变量是字符串而不是直接的颜色,这是为了后续能和透明度做一个动态的运算。比如我们这里有多个主题,分别为 light(默认),deep,dark,fantasy,我们可以这样定义:

    enum ModeEnum {light = 'light',deep = 'deep',dark = 'dark',fantasy = 'fantasy'}// 要完全的动态可配置,可以把这些值保存在服务端,动态获取// 然后在前端写个页面,用用取色器这个组件去设置颜色,保存进数据库// 这样就不需要前端写死变量了,从而达到更灵活的配置效果const cssVarsMap: Record<ModeEnum, Record<string, string>> = {light: {'--ice-color-base': '191, 219, 254','--ice-color-primary': '30, 58, 138','--ice-color-primary-content': '255, 255, 255'},deep: {'--ice-color-base': '125, 211, 252','--ice-color-primary': '79, 70, 229','--ice-color-primary-content': '255, 255, 255'},dark: {'--ice-color-base': '2, 132, 199','--ice-color-primary': '165, 180, 252','--ice-color-primary-content': '0,0,0'},fantasy: {'--ice-color-base': '8, 47, 73','--ice-color-primary': '224, 231, 255','--ice-color-primary-content': '0,0,0'}}

然后把这些变量的值动态设置在 html 上或者传入 ThemeProvider 中,就能达到切换的目的了。

简单的配置如下:

/** @type {import('tailwindcss').Config} */
module.exports = {theme: {extend: {colors: {primary: 'rgba(var(--ice-color-primary), <alpha-value>)','primary-content':'rgba(var(--ice-color-primary-content), <alpha-value>)',base: 'rgba(var(--ice-color-base), <alpha-value>)'}}},
}

同时由于我们定义的值是字符串,我们就可以利用这一点去自由的组合使用 rgba 构造函数,来决定它的透明度了。即利用CSS变量字符串的特性组合出, rgba(r,g,b,a) 的效果,这样写法上就非常自由了,同一个主题色,你可以写出 text-primary 直接使用 primary 色,也可以写出 text-primary/50 这样 50% 透明度的 primary 色。(这就是 <alpha-value> 占位符的目的)

这样我们定义组件的时候就可以用一个类名去动态引用变量了:

<template><buttonclass="bg-primary text-primary-content"><slot></slot></button>
</template>

这个组件背景主色,文字为主色的 content 色。

Variant 方案

不知道你有没有注意过,在 tailwindcss 自带的暗黑模式切换中,它使用的写法是 text-gray-800 dark:text-gray-200

这种的语义上非常的直观,看到它你就知道这个元素 color 默认情况下是 text-gray-800,暗黑模式下colortext-gray-200

同样它的生成也是在利用选择器/媒体选择器的优先级去覆盖,大体的原理如下:

border-white {--tw-border-opacity: 1;border-color: rgb(255 255 255 / var(--tw-border-opacity));
}:is(.dark .dark:border-slate-800) {--tw-border-opacity: 1;border-color: rgb(30 41 59 / var(--tw-border-opacity));
}

其中,这个 dark: 打头的条件就被称为 Variant,我们可以根据自己的需求,创建很多个 Variant 来定义并生成不同的 CSS 区块。同样我们可以去基于这种方法去扩展我们的主题。

比如我们这里我们还是有多个主题,分别为 light(默认),deep,dark,fantasy,我们可以这样定义:

const plugin = require('tailwindcss/plugin')/** @type {import('tailwindcss').Config} */
module.exports = {// 默认会添加 dark 的 Variant 和 .dark 的 css 生成块darkMode: 'class',plugins: [plugin(function ({ addVariant, addBase }) {addVariant('deep', ':is(.deep &)')addVariant('fantasy', ':is(.fantasy &)')}),],
}

这样我们像上面同样定义一个 button 组件就要这样写:

  <buttonclass="bg-pink-900 deep:bg-pink-600 dark:bg-pink-300 fantasy:bg-pink-100 text-white deep:text-gray-300 dark:text-gray-600 fantasy:text-gray-900"><slot></slot></button>

这样显然是非常冗长的,即使它还存在着一些可读性,但是还是瑜不掩瑕,而且使用 @apply 去提取的话,也是容易出错的。

而且还有一个致命的问题,这种方案每多一个主题就要加一个 Variant,这显然非常的不灵活的。所以说在不确定主题数量的情况下,这个方案是个灾难。主题色显然不是Variant适合的场景。

这个方案可能只适合暗黑模式这个特殊的场景。但是 CssVar 方案也能适配 暗黑模式 的。

所以主题色方案还是选择 CssVar 就行了。

2种方案在小程序上的示例

#小程序://tailwind/RvdAJVby6DXgZpa

复制到微信后打开,这里就不放小程序码了,省的被掘金判断是推广的文章。

或者微信搜索 tailwind 小程序进入查看效果。

之前的几篇

  1. 动态调整web系统主题? 看这一篇就够了

  2. 动态调整web主题(2) 萃取篇

  3. 动态调整web主题(3): 基于tailwindcss插件的主题色生成方案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/95673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 的数据管理与Docker 镜像的创建

------------------Docker 的数据管理--------------------- 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;。 1&#xff0e;数据卷 数据卷是一个供容器使用的特殊…

什么是Vue的JSX语法?如何使用JSX语法

Vue的JSX语法&#xff1a;更接近JavaScript的模板语言 Vue.js是一个流行的JavaScript框架&#xff0c;用于构建交互式的Web应用程序。虽然Vue通常使用模板语法来构建用户界面&#xff0c;但它也提供了JSX语法的支持&#xff0c;使开发人员能够更接近JavaScript的表达方式来构建…

分享几个优秀开源免费管理后台模版,建议收藏!

大家好&#xff0c;我是 jonssonyan 今天和大家分享一些免费开源的后台管理页面&#xff0c;帮助大家快速搭建前端页面。为什么要用模板&#xff1f;道理很简单&#xff0c;原因是方便我们快速开发。我们不应该花太多的时间在页面调整上&#xff0c;而应该把精力放在核心逻辑和…

re学习(37)DASCTF 2023 0X401七月暑期挑战赛 controflow

程序通过改变栈里面的返回地址来控制程序的控制流 从而达到混淆的效果 左侧有许多被hook的函数 在每个函数开头设置断点 然后观察程序的运行流程 会发现输入的数据会进行 异或 相加 异或 相减 相乘 异或等操作 要注意部分运算的索引是 从[10]开始的 具体思路参考&#xf…

黑豹程序员-架构师学习路线图-百科:JSON替代XML

文章目录 1、数据交换之王2、XML的起源3、JSON诞生4、什么是JSON 1、数据交换之王 最早多个软件之间使用txt进行信息交互&#xff0c;缺点&#xff1a;纯文本&#xff0c;无法了解其结构&#xff1b;之后使用信令&#xff0c;如&#xff1a;电话的信令&#xff08;拨号、接听、…

三十、【进阶】B-Trees的演变过程

1、索引结构 &#xff08;1&#xff09;二叉树 &#xff08;2&#xff09;B-Tree树 B-Tree树最大度数为5&#xff0c;代表每一个节点最多存储4个key(每个节点最多存储4个数据)&#xff0c;5个指针(可以指向5个子节点)。 2、演变过程&#xff08;最大度数为5&#xff09; &…

数据挖掘(3)特征化

从数据分析角度&#xff0c;DM分为两类&#xff0c;描述式数据挖掘&#xff0c;预测式数据挖掘。描述式数据挖掘是以简介概要的方式描述数据&#xff0c;并提供数据的一般性质。预测式数据挖掘分析数据建立模型并试图预测新数据集的行为。 DM的分类&#xff1a; 描述式DM&#…

记录本地部署Stable-diffusion所依赖的repositories和一些插件

今天按照其他文章的步骤拉取好了https://github.com/AUTOMATIC1111/stable-diffusion-webui后&#xff0c;点击webui-user.bat后发现&#xff0c;repositories和models还得慢慢拉取&#xff0c;好吧&#xff0c;GitHub Desktop&#xff0c;启动&#xff01; BLIP: https://git…

使用sqlmap获取数据步骤

文章目录 1.使用sqlmap获取所有数据库2.使用sqlmap获取当前连接数据库3.使用sqlmap获取当前数据库下所有表名4.使用sqlmap获取当前数据库下某个表下所有列名5.使用sqlmap获取当前数据库下某个表下指定字段的数据6.测试当前用户是否是管理员7.使用burpsqlmap批量检测8.脱库命令9…

c++使用ifstream和ofstream报错:不允许使用不完整的类型

学习《C Primer》关于IO库的部分&#xff0c;输入284页的的代码&#xff0c;出现了报错&#xff1a; 不允许使用不完整的类型 原来的代码&#xff1a; #include <iostream> #include <vector> using namespace std;int main(int argc, char **argv) {ifstream in…

Next.js 入门笔记

前言 之前初步体验了 React 的魅力, 又看文档理解了一下 useState 和 useEffect, 目前初步理解的概念是: useState 用来声明在组件中使用并且需要修改的变量 useEffect 用来对 useState 声明的变量进行初始化赋值 可能理解的不太准确, 不过大概差不多是这么个意思. 但是再往后…

【AI视野·今日NLP 自然语言处理论文速览 第四十七期】Wed, 4 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 4 Oct 2023 Totally 73 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Contrastive Post-training Large Language Models on Data Curriculum Authors Canwen Xu, Corby Rosset, Luc…

数字孪生、AR和VR如何改进数据中心设计

数据中心基础设施管理(DCIM)已存在多年&#xff0c;它在许多数据中心被广泛使用&#xff0c;但还没有普遍使用&#xff0c;由于两个因素&#xff0c;这种情况正在改变&#xff1a;数字化的概念正在普及&#xff0c;IT与运营技术(OT)系统(如建筑管理系统(BMS)和电源管理工具)的集…

从零开始的C++(五)

1.类和对象的补充 当对象是const修饰的常量时&#xff0c;形参中的this是隐含的&#xff0c;那么该如何写函数才能传常量对象呢&#xff1f;如果还是按照正常的方式写&#xff0c;则会出现实参是const修饰的&#xff0c;形参没有&#xff0c;出现了权限的扩大&#xff0c;无法…

Django 模型层的操作(Django-05 )

一 模型层的解读 Django中内嵌了ORM框架&#xff0c;不需要直接编写SQL语句进行数据库操作&#xff0c;而是通过定义模型类&#xff0c;操作模型类来完成对数据库中表的增删改查和创建等操作。 O 是object&#xff0c;也就类对象的意思。R 是relation&#xff0c;翻译成中文是…

快手直播显示请求过快

快手直播显示请求过快 问题描述情况一问题描述原因分析解决方案:情况二问题描述解决方法问题描述 在使用快手直播网页版时,如果我们的请求过于频繁,系统可能无法及时显示所需内容。这种情况下,我们会收到一个稍后重试的提示。一般有两种情况。一种是直接返回一段json,里面…

图像和视频上传平台Share Me

本文完成于 6 月&#xff0c;所以反代中&#xff0c;域名演示还是使用的 laosu.ml&#xff0c;不过版本并没有什么变化&#xff1b; 什么是 Share Me &#xff1f; Share Me 是使用 Next.js 和 PocketBase 的自托管图像和视频上传平台&#xff0c;具有丰富的嵌入支持和 API&…

【Qt基础篇】信号和槽

文章目录 一些常见的bug&#xff1a;字符集不对产生的错误VS平台中文乱码 QT的优点关于.pro文件QtCreator快捷键最简单的qt程序按钮的创建对象模型**Qt窗口坐标**体系信号和槽机制connect函数系统自带的信号和槽案例&#xff1a;实现点击按钮-关闭窗口的案例 自定义信号和槽案例…

【网络】路由器和交换机的区别

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1…

好奇喵 | Tor浏览器——访问.onion网址,揭开Dark Web的神秘面纱

前言 在之前的博客中&#xff1a; 1.Surface Web —&#xff1e; Deep Web —&#xff1e; Dark Web&#xff0c;我们解释了表层网络、深层网络等的相关概念&#xff1b; 2.Tor浏览器——层层剥开洋葱&#xff0c;我们阐述了Tor的历史和基本工作原理&#xff1b; 3.Tor浏览器…