Note-45089-23

Token ID: 1

ERC-721 1 Transfers

Metadata

{
  "title": "在 Nuxt.js 中配合 windicss 实现暗黑模式适配",
  "tags": [
    "post",
    "技术"
  ],
  "sources": [
    "xlog"
  ],
  "external_urls": [
    "https://daidr.xlog.app/nuxt-darkmode"
  ],
  "date_published": "2023-02-09T02:59:00.000Z",
  "content": "在 windicss 中,提供了媒体查询和 class 两种方式实现暗黑模式适配。而且比较省心的是——其提供的 `dark` 变体会自动根据选择的适配模式,生成对应的代码,可以有效避免写出一堆没用的css,看起来也比较清晰。\n\n为了方便控制,我们选择使用 class 的方式来切换暗黑模式(即给根元素赋予类名 `dark` 来切换到暗黑模式)\n\n## 基础样式\n\n首先,需要一些全局 css 来解决 windicss 无法覆盖的样式。\n\n### 滚动条颜色改变\n\n正常情况下,你可能会想用 `-webkit-scrollbar` 伪类,但是,其实有更优雅的写法。浏览器提供了一个 `color-scheme` css 属性,将其设置为dark,浏览器便会自动将页面内所有浏览器自带的元素渲染成暗色风格\n\n```css\nhtml.dark {\n    color-scheme: dark;\n}\n```\n\n### 图片亮度降低\n\n也很简单,应用一个 filter 就好了\n\n```css\nhtml.dark img {\n    filter: brightness(0.8);\n}\n```\n\n## 自动检测\n\n接下来就是重头戏了,如何判断并给html元素加上`dark`类名,毕竟windicss可不会帮我们自动处理。\n\n我们会在前端为用户提供一个下拉框,用户可以选择自动适应、保持暗黑模式、保持明亮模式\n\n![image](ipfs://bafkreicp5zplr4fmvcognexsawfcmrg5ldmgl2nqhnc5ly2bjkmodyluea)\n\n为了避免页面初载入时样式切换导致的闪屏,最终决定将该配置储存到cookie而非localstorage中,这样能够发挥ssr的作用,当用户强制暗黑/明亮时,服务端就能将类名写入html标签中。\n\n```javascript\nfunction readDarkModeInStorage() {\n  const darkMode = useCookie('darkMode')\n  const possibleValues = ['auto', 'dark', 'light']\n  if (darkMode.value && possibleValues.includes(darkMode.value)) {\n    return darkMode.value\n  } else {\n    return 'auto'\n  }\n}\n```\n\n上面是一个辅助函数,用于从储存中读出暗黑模式配置(服务端/客户端均可用)\n\n```javascript\nfunction setModeClass(isDark: boolean): void {\n  if (isDark) {\n    useHead({\n      htmlAttrs: { class: 'dark' },\n      meta: [{ name: 'theme-color', content: '#121212' }],\n    })\n  } else {\n    useHead({\n      htmlAttrs: { class: '' },\n      meta: [{ name: 'theme-color', content: '#ffffff' }],\n    })\n  }\n}\n```\n\n一个用于设置暗黑模式样式的工具函数,当传入布尔值时,会同时设置 html 的类名和 theme-color 的 meta 标签(ssr/csr均可用)\n\n使用了来自 VueUse 的 useHead 方法\n\n```javascript\nconst currentMode = ref(readDarkModeInStorage())\nconst preferredDark = usePreferredDark()\n\nwatchEffect(() => {\n  if (currentMode.value === 'auto') {\n    if (preferredDark.value) {\n      setModeClass(true)\n    } else {\n      setModeClass(false)\n    }\n  } else if (currentMode.value === 'dark') {\n    setModeClass(true)\n  } else if (currentMode.value === 'light') {\n    setModeClass(false)\n  }\n\n  useCookie('darkMode').value = currentMode.value\n})\n```\n\n这里便是关键,首先,读入配置并初始化到 `currentMode` 变量,接着,使用 VueUse 提供的 `usePreferredDark` 来获取当前浏览器的颜色模式。\n\n使用一个监听副作用的函数,当上面两个值发生改变时,调用 `setModeClass` 工具函数去完成最终的类名修改,并将配置写入 cookie。",
  "attributes": [
    {
      "value": "nuxt-darkmode",
      "trait_type": "xlog_slug"
    }
  ]
}