戴兜

戴兜的小屋

Coding the world.
github
bilibili
twitter

在 Nuxt.js 中配合 windicss 實現暗黑模式適配

在 windicss 中,提供了媒體查詢和 class 兩種方式實現暗黑模式適配。而且比較省心的是 —— 其提供的 dark 變體會自動根據選擇的適配模式,生成對應的代碼,可以有效避免寫出一堆沒用的 css,看起來也比較清晰。

為了方便控制,我們選擇使用 class 的方式來切換暗黑模式(即給根元素賦予類名 dark 來切換到暗黑模式)

基礎樣式#

首先,需要一些全局 css 來解決 windicss 無法覆蓋的樣式。

滾動條顏色改變#

正常情況下,你可能會想用 -webkit-scrollbar 偽類,但是,其實有更優雅的寫法。瀏覽器提供了一個 color-scheme css 屬性,將其設置為 dark,瀏覽器便會自動將頁面內所有瀏覽器自帶的元素渲染成暗色風格

html.dark {
    color-scheme: dark;
}

圖片亮度降低#

也很簡單,應用一個 filter 就好了

html.dark img {
    filter: brightness(0.8);
}

自動檢測#

接下來就是重頭戲了,如何判斷並給 html 元素加上dark類名,毕竟 windicss 可不會幫我們自動處理。

我們會在前端為用戶提供一個下拉框,用戶可以選擇自動適應、保持暗黑模式、保持明亮模式

image

為了避免頁面初載入時樣式切換導致的閃屏,最終決定將該配置儲存到 cookie 而非 localstorage 中,這樣能夠發揮 ssr 的作用,當用戶強制暗黑 / 明亮時,服務器就能將類名寫入 html 標籤中。

function readDarkModeInStorage() {
  const darkMode = useCookie('darkMode')
  const possibleValues = ['auto', 'dark', 'light']
  if (darkMode.value && possibleValues.includes(darkMode.value)) {
    return darkMode.value
  } else {
    return 'auto'
  }
}

上面是一個輔助函數,用於從儲存中讀出暗黑模式配置(服務器 / 客戶端均可用)

function setModeClass(isDark: boolean): void {
  if (isDark) {
    useHead({
      htmlAttrs: { class: 'dark' },
      meta: [{ name: 'theme-color', content: '#121212' }],
    })
  } else {
    useHead({
      htmlAttrs: { class: '' },
      meta: [{ name: 'theme-color', content: '#ffffff' }],
    })
  }
}

一個用於設置暗黑模式樣式的工具函數,當傳入布爾值時,會同時設置 html 的類名和 theme-color 的 meta 標籤(ssr/csr 均可用)

使用了來自 VueUse 的 useHead 方法

const currentMode = ref(readDarkModeInStorage())
const preferredDark = usePreferredDark()

watchEffect(() => {
  if (currentMode.value === 'auto') {
    if (preferredDark.value) {
      setModeClass(true)
    } else {
      setModeClass(false)
    }
  } else if (currentMode.value === 'dark') {
    setModeClass(true)
  } else if (currentMode.value === 'light') {
    setModeClass(false)
  }

  useCookie('darkMode').value = currentMode.value
})

這裡便是關鍵,首先,讀入配置並初始化到 currentMode 變量,接著,使用 VueUse 提供的 usePreferredDark 來獲取當前瀏覽器的顏色模式。

使用一個監聽副作用的函數,當上面兩個值發生改變時,調用 setModeClass 工具函數去完成最終的類名修改,並將配置寫入 cookie。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。