现代WEB主题色切换方案

随着 WEB 技术的发展,我们见证了网站和应用程序界面的主题色变得越来越多样化。这种多样性反映了用户对于个性化和视觉吸引力的需求,因此单一的主题色已经不再足够满足用户的多样化需求。为了更好地服务于不同用户群体的喜好和使用场景,网站和应用程序开始提供不同的预设主题以供用户切换。

这些预设主题主要涵盖了浅色主题深色主题跟随系统这三种基本的主题。深色主题为那些偏爱低调、沉稳的用户提供了舒适的浏览体验,尤其适用于夜间或低光环境下。而浅色主题则适合那些喜欢明亮、活泼色彩的用户,让他们在白天或明亮环境下享受清新的界面。跟随系统主题则根据用户的偏好或系统设置自动调整主题色,为用户提供了更智能、更个性化的体验。

🤔 稍提一嘴,深色主题还可以节省设备的电量。

浅色与深色主题切换

首先设置 color-schema 属性,告诉浏览器当前应用所支持的应用配色方案。

css 复制代码
:root {
  color-scheme: light dark;
}

然后,通过prefers-color-scheme 属性设置不同主题色下的样式。

prefers-color-scheme 用于检测用户是否有将系统的主题色设置为亮色或者暗色。通过这个属性,可以让网页根据用户系统的颜色模式自动调整显示效果。

这对于用户体验和可访问性都有很多好处。例如,如果用户喜欢在暗光环境下浏览网页,他们可以将系统设置为暗色模式,而网页可以根据这一设置自动切换到暗色主题,从而减少眼睛的疲劳和提高可读性。

此外,对于一些用户来说,暗色模式也是一种辅助功能,可以帮助他们更好地使用网页,比如对于光敏性癫痫患者来说,暗色模式可以减少光引发的癫痫发作的可能性。

css 复制代码
/* 在暗色模式下应用的样式 */
@media (prefers-color-scheme: dark) {
  body {
    background-color: #000;
    color: #fff;
  }
}

/* 在亮色模式下应用的样式 */
@media (prefers-color-scheme: light) {
  body {
    background-color: #fff;
    color: #000;
  }
}

跟随系统主题

通过媒体查询 + prefers-color-scheme 的方案,使得应用可以在浅色主题和深色主题之间切换,但此方案存在一些弊端,无法做到跟随系统主题的变化(毕竟系统主题由系统决定👀)。

如果要实现主题跟着操作系统主题的变化而变化,应该怎么做呢?🤔

(🤣既然 css不行,那就直接上 js )

随着查阅 MDN 相关的文档,可以使用 window 对象上的 matchMedia 方法监听当前是否匹配prefers-color-scheme的某一种情况。

js 复制代码
  const useDark = window.matchMedia('(prefers-color-scheme: dark)')
  useDark.addEventListener('change', function (evt) {
    const isDarkMode = evt.matches
    // 通过 isDarkMode 动态改变 document 的 class
    if (isDarkMode) { 
        document.documentElement.classList.add('dark')
    } else {
      document.documentElement.classList.remove('dark')
    }
  })

主题色切换优化

现代WEB网页开发大多采用的是组件化的开发方式,当系统的主题配色方案改变后,难以保证所有的组件过渡都能平滑的切换。

在 Chrome 111 中,推出了 View Transitions API。使得此 API 可以使得网页在 新旧快照之间进行一个平滑的过渡。

具体使用方法如下 :

ts 复制代码
function useViewTransition(event: MouseEvent) {
  const x = event.clientX
  const y = event.clientY
  const endRadius = Math.hypot(
    Math.max(x, innerWidth - x),
    Math.max(y, innerHeight - y),
  )

  let _isDark: boolean
  // startViewTransition 调用的时候 会获取当前页面的状态 ::view-transition-old(root)
  // 通过 startViewTransition 的回调函数,获取最新的页面的状态 ::view-transition-new(root)
  // 旧视图的动画效果从 opacity: 1 到 opacity: 0,而新视图则从 opacity: 0 过渡到 opacity: 1,从而形成淡入淡出。
  const transition = document.startViewTransition(() => {
    const root = document.documentElement
    _isDark = root.classList.contains('dark')
    const methodField = _isDark ? 'remove' : 'add'
    root.classList[methodField]('dark')
  })
  // 两者过渡的快照准备完成时,使用 Web Animations API 进行 动画过渡
  transition.ready.then(() => {
    const clipPath = [
      `circle(0px at ${x}px ${y}px)`,
      `circle(${endRadius}px at ${x}px ${y}px)`,
    ]

    document.documentElement.animate(
      {
        clipPath: _isDark ? [...clipPath].reverse() : clipPath,
      },
      {
        duration: 500,
        easing: 'ease-in',
        pseudoElement: _isDark // 运用于伪元素的过渡
          ? '::view-transition-old(root)'
          : '::view-transition-new(root)',
      },
    )
  })
}

除此之外,还需修改 view-transition css的默认行为,如下所示:

css 复制代码
::view-transition-old(root),
::view-transition-new(root) {
 /* 关闭默认的淡入淡出的效果 */
  animation: none;
  mix-blend-mode: normal;
}

.dark::view-transition-old(root) {
  z-index: 1;
}
.dark::view-transition-new(root) {
  z-index: 999;
}

::view-transition-old(root) {
  z-index: 999;
}
::view-transition-new(root) {
  z-index: 1;
}

参考资料

相关推荐
l1t32 分钟前
QWen 3.5plus总结的总结基准测试结果的正确方法
前端·数据库
kyriewen1144 分钟前
为什么我的代码在测试环境跑得好好的,一到用户电脑就崩?原来凶手躲在地址栏旁边
开发语言·前端·javascript·chrome·ecmascript·html5
小北方城市网1 小时前
JavaScript 实战 —— 实现一个简易的 TodoList(适合前端入门 / 进阶)
开发语言·前端·javascript
是上好佳佳佳呀1 小时前
【前端(二)】CSS 知识梳理:从编写位置到选择器优先级
前端·css
倾颜1 小时前
我是怎么把单 Tool Calling 升级成多 Tool Runtime 的
前端·后端·langchain
清汤饺子2 小时前
Superpowers:给 AI 编程 Agent 装上"工程化超能力"
前端·javascript·后端
踩着两条虫2 小时前
AI驱动的Vue3应用开发平台 深入探究(十三):物料系统之区块与页面模板
前端·vue.js·人工智能·架构·系统架构
weixin199701080162 小时前
《得物商品详情页前端性能优化实战》
前端·性能优化
帮我吧智能服务平台2 小时前
装备制造企业售后服务数字化:从成本中心到利润中心背景
java·前端·制造
qq_368019662 小时前
用 react 的react-syntax-highlighter 实现语法高亮、行号与多行错误行高亮
前端·react.js·前端框架