Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
內容首發于工粽號:程序員大澈,每日分享一段優質代碼片段,歡迎關注和投稿!
大家好,我是大澈!
本文約 800+ 字,整篇閱讀約需 1 分鐘。
今天分享一段優質 CSS 代碼片段,輕松實現一鍵切換主題顏色,在任何項目中都可用。
老規矩,先閱讀代碼片段并思考,再看代碼解析再思考,最后評論區留下你的見解!
[data-theme='default'] {
--font-primary: #fff;
--background-main: #0678be;
}
[data-theme='black'] {
--font-primary: #fff;
--background-main: #393939;
}
<html lang="en" data-theme="default"></html>
body {
color: var(--font-primary);
background-color: var(--background-main);
}
分享原因
這段代碼可以輕松實現網頁主題的切換,且在各種項目中通用。
先定義不同主題的 CSS 變量,再通過 JavaScript 動態更改 data-theme 屬性,從而實現頁面樣式的動態變化。
這種方法不僅簡化了主題管理,還提高了代碼的可讀性和維護性,是我們項目中一般且常用的實現方式之一。
代碼解析
1. 定義主題變量
CSS變量:聲明自定義CSS屬性,它包含的值可以在整個文檔中重復使用。屬性名需要以兩個減號(--)開始,屬性值則可以是任何有效的 CSS 值。
CSS屬性選擇器:匹配具有特定屬性或屬性值的元素。例如[data-theme='black'],將選擇所有 data-theme 屬性值為 'black' 的元素。
使用 [data-theme='default'] 和 [data-theme='black'] 選擇器,根據 data-theme 屬性的值定義不同的主題樣式。
定義了兩個 CSS 變量 --font-primary 和 --background-main,分別表示字體顏色和背景顏色。
2. 指定默認主題
在 <html> 元素上添加 data-theme="default",指定默認主題為 default 。
后面用 js 動態切換 data-theme 屬性值,然后 CSS 屬性選擇器將自動選擇對應的 CSS 變量。
3. 應用 CSS 變量
Var函數:用于使用 CSS 變量。第一個參數為 CSS 變量名稱,第二個可選參數作為默認值。
使用 var(--font-primary) 和 var(--background-main) 來引用之前定義的 CSS 變量。
這里設置 body 元素的 color 和 background-color 屬性,分別引用 --font-primary 和 --background-main 變量,在項目中按需設置對應的元素即可。
vue使用scss、less切換主題(scss篇),進來就是賺到
**引言**
在Vue項目開發中,樣式管理是至關重要的環節。SCSS作為一種CSS預處理器,以其強大的變量、嵌套、混入等特性深受開發者喜愛。本文將聚焦于如何在Vue項目中通過SCSS實現主題切換功能,助你輕松打造可定制化的Web應用界面。
## **一、搭建基于SCSS的Vue項目**
首先,我們需要在Vue CLI創建的項目中啟用并配置SCSS支持。
### **1.1 創建Vue項目并安裝相關依賴**
```bash
vue create my-project
cd my-project
npm install sass-loader node-sass -D
```
### **1.2 配置webpack處理SCSS文件**
打開或創建`vue.config.js`文件,并添加以下配置:
```javascript
module.exports = {
css: {
loaderOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss"; // 引入全局變量文件`
}
}
}
};
```
這里引入了一個全局的`variables.scss`文件,用于存儲主題相關的變量。
## **二、定義主題變量與組件樣式**
### **2.1 定義主題變量**
在`src/styles/variables.scss`中定義基礎主題顏色:
```scss
$primary-color: #007bff;
$secondary-color: #6c757d;
// ... 其他主題變量
```
### **2.2 組件中引用主題變量**
在組件的SCSS文件中,可以這樣引用全局變量:
```scss
// src/components/MyComponent.vue
<style lang="scss">
.my-component {
background-color: $primary-color;
color: $secondary-color;
}
</style>
```
## **三、動態切換主題**
### **3.1 創建多個主題變量文件**
為了實現主題切換,我們可以創建多個主題變量文件,如`variables_dark.scss`和`variables_light.scss`。
### **3.2 在JavaScript中切換主題**
```javascript
// src/store/index.js 或者其他邏輯控制模塊
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
theme: 'light' // 初始主題為“亮色”
},
mutations: {
switchTheme(state, theme) {
state.theme = theme; // 更新主題狀態
// 更改全局SCSS變量數據
const styleTag = document.createElement('style');
styleTag.innerHTML = `
@import '@/styles/variables_${state.theme}.scss';
`;
document.head.appendChild(styleTag);
}
},
actions: {
changeToDarkTheme({ commit }) {
commit('switchTheme', 'dark');
},
changeToLightTheme({ commit }) {
commit('switchTheme', 'light');
}
}
});
```
### **3.3 調用主題切換方法**
在需要觸發主題切換的地方調用actions,例如在按鈕點擊事件中:
```html
<template>
<button @click="changeTheme">切換主題</button>
</template>
<script>
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions(['changeToDarkTheme', 'changeToLightTheme']),
changeTheme() {
if (this.$store.state.theme === 'light') {
this.changeToDarkTheme();
} else {
this.changeToLightTheme();
}
}
}
};
</script>
```
## **四、進階優化:動態注入SCSS變量**
由于上述方案每次切換主題都會創建新的`<style>`標簽,效率并不理想。更優雅的方式是利用Webpack的插件實現動態替換CSS變量。
一種可行的方法是使用`webpack-theme-color-replacer-plugin`或者其他類似的插件,在編譯階段替換指定的CSS變量值,以達到動態切換主題的效果。
總結:
本文詳細介紹了如何在Vue項目中利用SCSS實現主題切換功能,從定義主題變量、編寫組件樣式,再到通過Vuex管理主題狀態以及JS操作DOM動態更改主題。雖然直接通過插入`<style>`標簽的方式簡單易懂,但實際生產環境中推薦采用Webpack插件進行更高效的變量替換。掌握這一技術,無疑將極大地提升你的Vue項目靈活性與用戶體驗。
一種構建靈活的系統頁面主題方案
前置技術點
閱讀此篇文章前,最好有下列知識
css 基礎知識
dart-sass 預處理器編程
webpack 以及 postcss
tailwindcss 含有 jit 的 v2/v3
前言
我們在日常生活中,不論是訪問網站,手機App,還是小程序,時常會用到 切換主題 這個功能。它能夠為用戶提供一定的自定義顯示界面的能力,同時手機系統級別的主題也能夠更換,比如 light(明亮模式) 和 dark(黑暗模式)。
那么如何讓我們編寫的應用,在改動不大的情況下,能夠快速的適配多個主題呢?
這就需要設計一個方案了。
方案設計
方案參考
這里我們以程序員們最熟悉的 Github 為例,它的主題切換是這樣做的:
它在 根元素 那預設了幾套 css 變量值, 然后通過 js 去動態修改 html 根元素上的 data-color-mode 和 data-dark-theme 這些屬性的值,從而讓不同的 css 選擇器選中這個根元素,并以此來動態的切換 :root 中的 css 變量的值。
同時這些變量都被廣泛的使用在各種的 原子化的 class 和 @apply 中,一旦變量一換,所有使用到這些class的控件和布局都收到影響,自然整個主題就改變了。
1. 提煉css變量
首先我們第一步要做的就是提煉css變量,這些主要由設計師提供。
這里以顏色為例,主要包含 同個顏色的多態,控件各個狀態的顏色,提示警告錯誤,字體中,標題,副標題,正文,提示的顏色 等等。當然像字體大小,陰影這類也是同樣的。
這方面就不細說了,在提取到變量之后我們就可以開始進行命名工作:
// constants.scss // 這是一個 scss 的 map數據結構,保存默認的初始值 $root-vars:( --color-fg-default: #adbac7, --color-fg-muted: #768390, --color-fg-subtle: #545d68, --color-fg-on-emphasis: #cdd9e5, --color-scale-gray-0: #cdd9e5, --color-scale-gray-1: #adbac7, --color-scale-gray-2: #909dab, --color-scale-gray-3: #768390, // ... )
可以注意到,在維護的變量中,顏色占了絕大部分,而且我們保存的都是顏色的hex格式,并沒有按照rgba的格式,把透明度(opacity)保存下來, 這是為什么? 答案會在后面揭曉。
接著,維護完這個sass:map ,我們編寫一個工具類 util.scss 來把顏色變量轉化為字符串:
// util.scss @use 'sass:color'; @use 'sass:meta'; @function getRgbString($color) { @if (meta.type-of($color) == color) { @return color.red($color) color.green($color) color.blue($color); } @else { @return $color; } }
然后在全局樣式 global.scss 中添加:
// global.scss @use './constants.scss' as C; @use './util.scss' as Util; :root { @each $var, $color in C.$root-vars { #{$var}: Util.getRgbaString($color); } }
這樣我們的那些變量默認值字符串就添加進了 :root 根元素中:
/* result */ :root{ --color-canvas-default-transparent: 34 39 46; --color-marketing-icon-primary: 108 182 255; --color-marketing-icon-secondary: 49 109 202; --color-diff-blob-addition-num-text: 173 186 199; --color-diff-blob-addition-fg: 173 186 199; --color-diff-blob-addition-num-bg: 87 171 90; --color-diff-blob-addition-line-bg: 70 149 74; --color-diff-blob-addition-word-bg: 70 149 74; --color-diff-blob-deletion-num-text: 173 186 199; ... }
這里注意全局變量中存儲的是字符串,并不是顏色變量本身。
但是有了這些,沒有對應的 class 和 scss 變量,我們還是很不好使用這些變量的,那么怎么進行工程化來提升我們的開發效率呢?接下來重點來了。
2. scss 與 js通信,動態生成 scss 變量與原子化 class
首先編寫 export.scss 用于暴露對象給 js 使用:
// export.scss @use './constants.scss' as C; @use './util.scss' as Util; :export { @each $var, $color in C.$root-vars { #{$var}: Util.getRgbaString($color); } }
然后利用 webpack sass-loader 中 js 和 scss 的通信方法,就可以生成:
variables.scss (全局scss變量文件)
extendColors.cjs (tailwindcss colors 配置文件)
// generator.js 生成器 import variables from '@/assets/scss/export.scss' // 簡易的去除前綴 removeColorPrefix(str) { return str.substring(8) } // 此時的 variables 是一個 object // 那么scss全局變量的模板生成為: scssFilterShadow(str) { return `rgb(var(${str}))` } // scss模板為 ${{ removeColorPrefix(k) }}:{{ scssFilterShadow(k) }}; // 此時 原子化的 `tailwindcss colors` 文件生成為: jsFilterShadow(str) { return `withOpacityValue('${str}')` } // tailwindcss模板為 '{{ removeColorPrefix(k) }}':{{ jsFilterShadow(k) }},
通過這種方式,我們把生成的結果寫入 variables.scss 和 extendColors.cjs 文件內,從而便捷把第一步中維護的如此之多的 css變量,全部快速方便的轉化為同等的 scss變量 和 tailwindcss 配置
3. 全局scss文件變量注入
生成 variables.scss后,我們可以配置一下 sass-loader 來讓其中的變量無需顯式引入,即可在全局生效:
// sass-loader { additionalData: '@use "@/assets/scss/variables.scss" *;', }
這樣我們就可以在任意的 vue <style>, 或者 .scss 文件內使用到所有 variables.scss 中聲明的變量了。
4. 原子化的 class 生成
生成 extendColors.cjs 后,我們在里面添加:
function withOpacityValue(variable) { return ({ opacityValue }) => { if (opacityValue === undefined) { return `rgb(var(${variable}))` } return `rgb(var(${variable}) / ${opacityValue})` } }
這是為了結合 jit引擎,來動態的調整所有顏色的透明度。有了它,我們就能編寫出以下的代碼:
h1{ @apply text-header-text; // 等價于 // color: rgb(var(--color-header-text)) } h2{ @apply text-header-text/70; // 等價于 // color: rgb(var(--color-header-text) / 0.7) }
這也是我們要給根元素中的 css變量 賦值為 R G B 格式的原因了!
本質上講,是我們在利用原生 css 中 rgb(rgba是rgb的別名) 構造方法來創建顏色變量:
/* rgb的函數Syntax */ rgb(255,255,255) /* white */ rgb(255,255,255,.5) /* white with 50% opacity */ rgb(255 255 255) /* CSS Colors 4 space-separated values */ rgb(255 255 255 / .5); /* white with 50% opacity, using CSS Colors 4 space-separated values */
從上面這段代碼片段中,我們可以看到,列出的 rgb(R G B / A)就是現在使用的方案。
當然我們也可以更改上述的 getRgbString 和 withOpacityValue 這2個方法,把 , 這個分隔符加入進去,再把 / 去除,從而使用它 rgb(R,G,B,A) 這個構造方式。
這樣我們在使用時就可以生成出這樣的樣式:
.neutral{ background-color: rgb(var(--color-neutral-muted)); &:hover{ background-color: rgb(var(--color-neutral-muted) / 0.4); } }
是不是非常的靈活?
接下來只要把 extendColors.cjs 導入進 tailwind.config.js 配置中,就可以自動生成 class 和 vscode 的智能提示了:
// tailwind.config.js const extendColors = require('./client/theme/extendColors.cjs') const colors = require('tailwindcss/colors') module.exports = { // ... theme:{ extend:{ colors:{ ...extendColors.colors, } //... }, colors:{ transparent: 'transparent', current: 'currentColor', black: colors.black, white: colors.white, gray: colors.gray, }, // ... } // ... }
這樣,我們只需要把主題變更依賴的變量們,寫進各種控件,layout,容器中去,所有的 css 變量就生效了,切換主題就非常的方便。
5. 動態修改根節點變量
很多場景下我們的應用主題,不是從前端維護的幾套預設方案中進行選擇,而是由用戶自定義配置,保存在數據庫中,每次請求后端才能獲取到。
這種獲取方式意味著前端這里,只保留一套默認的預設方案。所以我們通常會在獲取到后端給的主題數據后,動態的修改 css變量 的值。
具體怎么做呢?本質上就是調用 CSSStyleDeclaration.setProperty(),來設置 document.documentElement 的變量值。
為了讓它更好用,我們可以進行封裝,并建立一套瀏覽器本地的緩存機制,這些在此不再敘述,條條大道通羅馬。
兼容性
注意此方案是放棄 IE 的! (都上 tailwindcss 了),其余瀏覽器兼容良好。
總結
這種方式,實際上利用了很多的 css, sass, webpack,tailwindcss 的特性,筆者回過頭來看,發現這個方案在實現后,好用是非常好用的。
變量,原子化class, 公共提取和智能提示一應俱全,就是要對上面一些技術點有比較充分的理解。
如果您對此篇文章有建議或者更好的方案,也歡迎聯系筆者一起探討。
筆者的聯系方式
附錄
源碼
*請認真填寫需求信息,我們會在24小時內與您取得聯系。