換膚功能(scss、css變量)

博客地址:https://ainyi.com/104

產品 SaaS 化,通常需要有換膚功能

這裏簡單記錄一下主題色及其衍生色(高亮、淺色)的更換功能

scss 全局定義

每個頁面都有顏色,那麼應該把顏色值定義在 global.scss 文件中,通過變量定義,比如

$color-primary: #4762FE;
$color-primary-dark: #3245D9;
$color-primary-light: #C2D1FF;
$color-primary-lightest: #EBF0FF;
$color-primary-transparency: rgba(71,98,254,0.1);

每個頁面的樣式表引入此文件

@import './global.scss';

// 使用例子
.demo {
  color: $color-primary
}

這樣,只要更改 scss 中全局變量的顏色值,就可以同步更改項目的顏色值

css 變量定義

思考如何注入顏色值?

這裏就用到 css 的變量函數了:var()
之前有談到使用 css 的變量以及賦值方法:Bilibili [冬] banner 早中晚切換效果

var() 函數用於插入自定義的屬性值

兩個參數:property,value
property:必填,自定義屬性的名稱,必需以 -- 開頭
value:可選,備用值,在屬性不存在的時候使用

比如

body {
  --tempColor: #fff;
}
.temp {
  color: var(--tempColor)
}

設置其屬性:DOM.style.setProperty(name, value)


這裏就很清楚了,scss 中全局變量引入的是 var() 函數的變量值

獲取衍生色

主題色是隻有一個,需要通過主題色來獲取其衍生顏色(高亮、淺色等)

scss 中提供一個方法:mix()
Mix 函數是將兩種顏色根據一定的比例混合在一起,生成另一種顏色。其使用語法如下:

mix($color-1,$color-2,$weight);

$color-1 和 $color-2 指的是你需要合併的顏色,顏色可以是任何表達式,也可以是顏色變量
$weight 爲 合併的比例(選擇權重),默認值爲 50%,其取值範圍是 0~1 之間。它是每個 RGB 的百分比來衡量,當然透明度也會有一定的權重
如果指定的比例是 25%,意味着第一個顏色所佔比例爲 25%,第二個顏色所佔比例爲75%

此外,scss 還有一個 HSL 函數,也是設置顏色值的方法,這裏就不過多探究了


坑來了
當我把 var() 函數獲取的顏色值放進 mix 函數中,居然報錯:

SassError: argument $color-2 of mix($color-1, $color-2, $weight: 50%) must be a color

mix 函數無法使用帶有 var() 函數變量的參數,HSL 函數也是;但普通變量是可以的


最終只能使用 js 函數通過主題色來獲取衍生顏色

這裏提供幾個方法:

// str: 十六進制顏色值,n:透明度
export function colorRgba(str, n) {
  // 十六進制顏色值的正則表達式
  let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
  let sColor = str.toLowerCase()
  n = n || 1
  // 十六進制顏色轉換爲RGB格式
  if (sColor && reg.test(sColor)) {
    let sColorChange = getRgbNum(sColor)
    return 'rgba(' + sColorChange.join(',') + ',' + n + ')'
  } else {
    return sColor
  }
}
// 獲取 rgb 顏色值
function getRgbNum(sColor) {
  if (sColor.length === 4) {
    let sColorNew = '#'
    for (let i = 1; i < 4; i += 1) {
      // 補全顏色值 例如:#eee,#fff等
      sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
    }
    sColor = sColorNew
  }
  // 處理六位顏色值
  let sColorChange = []
  for (let i = 1; i < 7; i += 2) {
    // 核心代碼,通過parseInt將十六進制轉爲十進制,parseInt只有一個參數時是默認轉爲十進制的,第二個參數則是指定轉爲對應進制
    sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
  }
  return sColorChange
}
// 加深或減弱顏色值
export function lightDarkenColor(color, num) {
  let colorArr = getRgbNum(color)
  let sColorChange = []
  for (let i = 0; i < colorArr.length; i++) {
    let val = colorArr[i] + num
    if (val < 0) {
      val = 0
    }
    if (val > 255) {
      val = 255
    }
    sColorChange.push(val)
  }
  return 'rgba(' + sColorChange.join(',') + ',1)'
}

最後只需要在路由全局前置守衛中計算顏色值,並賦值到 css 變量上,在 scss 全局變量中用 var() 函數引入 css 變量(各種顏色值)

換膚流程

通過接口獲取主題色 --> js 計算衍生色值 --> 賦值到 css 變量 --> scss 全局變量用 var() 函數引入 css 變量 --> 頁面樣式引用 scss 全局顏色值

使用例子

global.scss

$color-primary: var(--primaryColor, #4762FE);
$color-primary-dark: var(--primaryDarkColor, #3245D9);
$color-primary-light: var(--primaryLightColor, #C2D1FF);
$color-primary-lightest: var(--primaryLightestColor, #EBF0FF);
$color-primary-transparency: var(--primaryTransparencyColor, rgba(71,98,254,0.1));

路由守衛:

router.beforeEach((to, from, next) => {
  const primaryColor = getConfigStyle() // 從接口獲取的主題色
  const colorObj = {
    primaryColor: primaryColor,
    primaryDarkColor: lightDarkenColor(primaryColor, -20),
    primaryLightColor: colorRgba(primaryColor, 0.3),
    primaryLightestColor: colorRgba(primaryColor, 0.12),
    primaryTransparencyColor: colorRgba(primaryColor, 0.1)
  }
  Object.entries(colorObj).forEach(ele => {
    // 逐個設置 css 變量到 body 上
    document.body.style.setProperty(`--${ele[0]}`, ele[1])
  })
  next()
})

博客地址:https://ainyi.com/104

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章