Theme customization is really easy with CSS variables

Continue to create, accelerate growth! This is the sixth day of my participation in the "Nuggets Daily New Plan · October Update Challenge", click to view the details of the event

This article is the sixth part of the Varlet component library source code theme reading series, which Varletsupports custom themes and dark mode. In this article, we will take a detailed look at the implementation of these two.

Theme customization

VarletcssStyles are organized through variables. What is a cssvariable is actually very simple. First, declare a custom cssattribute, and you can declare it on any element, but only the descendants of the element can use it, so if you want to declare all global elements If it can be used, it can be set to the root pseudo-class :root:

:root {
  --main-bg-color: red;
}
复制代码

As shown in the code, cssthe custom attribute of the variable is required and needs to --start with.

Then call the function on any element that needs to use the style var():

div {
  background-color: var(--main-bg-color);
}
复制代码

Whenever the value of the property is changed --main-bg-color, everything that uses the style variable will be updated, so this is what the theme customization relies on.

VarletThe style variables of components are generally divided into two types: basic and component's own.

The public basic style variables are defined in the varlet-ui/src/styles/directory:

Every component will import this file, such as Buttoncomponents:

In addition, each component will also have its own variables, such as Buttoncomponents:

It is also very simple to modify the default value, just override it. Dynamically updating the style at runtime can also directly modify the style variables of the root node. In addition, Varleta component is provided to help us do this. Let's see how this component is implemented.

component call

Component-based invocation can customize component styles in a scope to avoid global pollution. Example usage:

<script setup>
import { ref, reactive } from 'vue'

const state = reactive({
  score: 5,
})

const styleVars = ref({
  '--rate-primary-color': 'var(--color-success)',
})
</script>

<template>
  <var-style-provider :style-vars="styleVars">
    <var-rate v-model="state.score" />
  </var-style-provider>
</template>
复制代码

StyleProviderThe component source code is as follows:

<script lang="ts">
import { defineComponent, h } from 'vue'
import { formatStyleVars } from '../utils/elements'
import { call, createNamespace } from '../utils/components'

const { n } = createNamespace('style-provider')

export default defineComponent({
  name: 'VarStyleProvider',
  props: {
    styleVars: {
      type: Object,
      default: () => ({}),
    },
  },
  setup(props, { slots }) {
    return () =>
      h(
        'div',
        {
          class: n(),
          style: formatStyleVars(props.styleVars),
        },
        call(slots.default)
      )
  },
})
</script>
复制代码

The implementation is as simple as creating an divelement to wrap the component, and then setting cssvariables divon it so that those cssvariables only affect its descendant elements.

function call

In addition to using components, you can also use functions, but you can only update styles globally:

<script setup>
import { StyleProvider } from '@varlet/ui'

let rootStyleVars = null

const darkTheme = {
  '--color-primary': '#3f51b5'
}

const toggleRootTheme = () => {
  rootStyleVars = rootStyleVars ? null : darkTheme
  StyleProvider(rootStyleVars)
}
</script>

<template>
  <var-button type="primary" block @click="toggleRootTheme">切换根节点样式变量</var-button>
</template>
复制代码

StyleProviderThe function is as follows:

const mountedVarKeys: string[] = []

function StyleProvider(styleVars: StyleVars | null = {}) {
    // 删除之前设置的css变量
    mountedVarKeys.forEach((key) => document.documentElement.style.removeProperty(key))
    mountedVarKeys.length = 0
    // 将css变量设置到根元素上,并且添加到mountedVarKeys数组
    const styles: StyleVars = formatStyleVars(styleVars)
    Object.entries(styles).forEach(([key, value]) => {
        document.documentElement.style.setProperty(key, value)
        mountedVarKeys.push(key)
    })
}
复制代码

The implementation is also very simple, directly setting the cssvariable to the htmlnode, and adding it to an array for deletion operations.

dark mode

VarletBuilt-in support for dark mode is provided by:

<script setup>
import dark from '@varlet/ui/es/themes/dark'
import { StyleProvider } from '@varlet/ui'

let currentTheme = null

const toggleTheme = () => {
  currentTheme = currentTheme ? null : dark
  StyleProvider(currentTheme)
}
</script>

<template>
  <var-button block @click="toggleTheme">切换主题</var-button>
</template>
复制代码

The previous StyleProvidermethod is also called, so the implementation principle is also through cssvariables, which is actually a built-in set of variables in dark mode css:

Summarize

It can be found that using cssvariables to achieve theme customization and dark mode is very simple, and the compatibility is also very good. If you have a need for skinning, you can give priority to using it.

Guess you like

Origin juejin.im/post/7155281417990045732