Dynamic adjustment of system theme color (4): Exploration of CssVar and Variant solutions
- Dynamically adjusting the system theme color (4): Exploration of CssVar and Variant solutions
- Preface
- Introduction and comparison of plans
- CssVar (CSS variable scheme)
- Combination of CSS variable scheme and tailwindcss
- Variant plan
- Examples of 2 solutions on mini programs
- Previous articles
Foreword
This is already the fourth article on dynamically adjusting the system theme color. In the blink of an eye, 2 years have passed since the first article was released. As time goes by, the understanding of technology is constantly improving, and solutions are constantly being improved and introduced. This article discusses the 2
solution for the system theme color: CssVar
and Variant
.
Introduction and comparison of plans
If you have not read the previous three articles, you may not intuitively know what they mean when you first see these 2
words. Let me briefly introduce what they are and their principles.
CssVar (CSS variable scheme)
This plan is very simple. The general idea is that we define in advance how many colors will be used throughout the entire design specification. Then define them as CSS
variables, and then change the entire theme by changing the value of the CSS
variable.
For example, we can define it like this:
:root{<!-- --> --prism-background: #f4f4f4; } /*dark*/ html.dark{<!-- --> --prism-background: #181818; } body{<!-- --> background-color: var(--prism-background); }
This method defines other themes under the :root/html
selector. Essentially, it uses the priority of the selector to overwrite the original definition of CSS
variables. value to achieve the switching effect. This solution is very versatile. Many component libraries you see use this solution, such as element-plus
/ vant
and so on (antd
is not)
CSS
variables will look for definitions recursively upward from where they are used, so if we want to overwrite variables defined in :root
, we can directly add them to the variable defined in :root
. Define a value where used to replace it to achieve the overwriting effect.
Therefore, we can encapsulate a component ThemeProvider
, define a div
element to wrap a slot, and then dynamically set the CSS
variable in this element, thereby achieving the effect of switching local CSS
variables in the slot. (Does it feel familiar?)
Combination of CSS variable scheme and tailwindcss
Of course, CSS
variable scheme and tailwindcss
can be combined very well. We only need to add theme< in
tailwind.config.js
in advance. Just expand and define variables in advance in /code>.
However, it is a little different from the above method. The CSS
variable we define here is a string instead of a direct color. This is to enable a dynamic operation with transparency later. For example, we have multiple themes here, namely light
(default), deep
, dark
, fantasy
. We It can be defined like this:
enum ModeEnum {<!-- --> light = 'light', deep = 'deep', dark = 'dark', fantasy = 'fantasy' } // To be completely dynamically configurable, you can save these values on the server and obtain them dynamically // Then write a page on the front end, use the color picker component to set the color, and save it in the database // This eliminates the need to hard-code variables on the front end, thereby achieving a more flexible configuration effect. 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' } }
Then dynamically set the values of these variables on html
or pass them into ThemeProvider
to achieve the purpose of switching.
A simple configuration is as follows:
/** @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>)' } } }, }
At the same time, since the value we define is a string, we can use this to freely combine the rgba
constructor to determine its transparency. That is, using the characteristics of CSS
variable strings to combine the effect of rgba(r,g,b,a)
, this way the writing method is very free, and the same theme color , you can write text-primary
directly using the primary
color, or you can write text-primary/50
like this 50%
The primary
color of transparency. (This is the purpose of the
placeholder)
In this way, when we define a component, we can use a class name to dynamically reference the variable:
<template> <button class="bg-primary text-primary-content"> <slot></slot> </button> </template>
The background color of this component is the main color, and the text is the main color of content
.
Variant plan
I don’t know if you have noticed that in the dark mode switch that comes with tailwindcss
, the writing method used is text-gray-800 dark:text-gray-200
.
This kind of semantics is very intuitive. When you see it, you will know that this element color
is text-gray-800
by default. In dark mode, color
is text-gray-200
.
Similarly, its generation is also covered by the priority of Selector
/Media Selector
. The general principle is as follows:
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)); }
Among them, the condition starting with dark:
is called Variant
. We can create many Variant
according to our own needs to define and generate Different CSS
blocks. Similarly, we can expand our theme based on this method.
For example, we still have multiple themes here, namely light
(default), deep
, dark
, fantasy
, we can define it like this:
const plugin = require('tailwindcss/plugin') /** @type {import('tailwindcss').Config} */ module.exports = {<!-- --> //Dark Variant and .dark css generation blocks will be added by default darkMode: 'class', plugins: [ plugin(function ({<!-- --> addVariant, addBase }) {<!-- --> addVariant('deep', ':is(.deep & amp;)') addVariant('fantasy', ':is(.fantasy & amp;)') }), ], }
In this way, if we define a button
component as above, we will write it like this:
<button class=" 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>
This is obviously very verbose, even if it is still somewhat readable, but it is still flawless, and it is also error-prone to use @apply
to extract it.
And there is a fatal problem. This solution requires adding a Variant
for each additional theme, which is obviously very inflexible. So when the number of topics is uncertain, this solution is a disaster. The theme color is obviously not a suitable scenario for Variant
.
This solution may only be suitable for the special scenario of dark mode. But the CssVar
solution can also adapt to Dark Mode
.
So just choose CssVar
for the theme color scheme.
Examples of two solutions on mini programs
#小program://tailwind/RvdAJVby6DXgZpa
After copying it to WeChat and opening it, the applet code will not be placed here to avoid being judged by the Nuggets as a promotional article.
Or search the tailwind
applet on WeChat to view the effect.
Previous articles
-
Dynamically adjust the web system theme? Just read this article
-
Dynamically adjust web themes (2) Extraction
-
Dynamically adjust web themes (3): theme color generation scheme based on tailwindcss plug-in