前端如何实现黑夜模式

时间:2021-1-8 作者:admin

深色模式为目前网络发展的一大趋势,可以看到大量的网站为了提高网站的体验都添加了深色模式。深色模式在光线不足的情况下看起来不会那么刺眼,能够很好的保护我们的眼睛。
在这边文章中主要讲如何使用CSS和JS实现深色模式和浅色模式的任意切换

分析需求

假设有这么一个页面,我们需要自由切换深色模式和浅色模式。那么就需要在不同模式使用不同的css,这里可以通过两种方式一种是直接引入不同的css文件,另外一种通过更改css变量值的方式进行更改样式,下面是浅色模式的截图

具体实现

首先定义浅色模式的变量名和变量值

:root {
  --primary-bg: #eee;
  --primary-fg: #000;
  --secondary-bg: #ddd;
  --secondary-fg: #555;
  --primary-btn-bg: #000;
  --primary-btn-fg: #fff;
  --secondary-btn-bg: #ff0000;
  --secondary-btn-fg: #ffff00;
}

当切换场景的时候需要更改css变量的值,更改如下:

:root {
  --primary-bg: #282c35;
  --primary-fg: #fff;
  --secondary-bg: #1e2129;
  --secondary-fg: #aaa;
  --primary-btn-bg: #ddd;
  --primary-btn-fg: #222;
  --secondary-btn-bg: #780404;
  --secondary-btn-fg: #baba6a;
}

可以看到当切换到深色模式的时候,变量使用了更加暗的颜色,从而实现深色模式

更改css

如何切换到暗模式有多种解决方法,在这里我们使用媒体查询,prefers-color-scheme这个媒体查询能够获取到用户的系统是否切换到了深色主题,具体如下:

@media (prefers-color-scheme: dark) {
  :root {
    --primary-bg: #282c35;
    --primary-fg: #fff;
    --secondary-bg: #1e2129;
    --secondary-fg: #aaa;
    --primary-btn-bg: #ddd;
    --primary-btn-fg: #222;
    --secondary-btn-bg: #780404;
    --secondary-btn-fg: #baba6a;
    --image-opacity: 0.85;
  }
}

如果希望用户可以通过选择系统的设置来切换浅色模式还是深色模式,那么上面这种方式就足够了。浏览的网站能够通过系统设置选择不同的样式
但是上面这种方式存在一个问题,就是用户希望这个页面的模式不要跟随系统配置的更改而更改。用户可以主动更改网站的模式,那么上面这种方式就不合适了

手动选择模式

思路就是通过控制js来给元素添加不同的class,不同的class拥有不同的样式。首先添加在html中添加一个按钮用于切换不同的模式

<button id="toggle-button">toggle</button>
<script>
  const toggleButton = document.querySelector('#toggle-button')
</script>

然后需要地方存储用户的偏好设置,这里使用localStorage来存储用户的选择。
然后给按钮添加事件用于切换主题,下面是具体的代码

  const toggleButton = document.querySelector('#toggle-button')

  toggleButton.addEventListener('click', (e) => {
    darkMode = localStorage.getItem('theme');
    if (darkMode === 'dark') {
      disableDarkMode();
    } else {
      enableDarkMode();
    }
  });

  function enableDarkMode() {
    localStorage.setItem('theme', 'dark');
  }

  function disableDarkMode() {
    localStorage.setItem('theme', 'light');
  }

现在我们就可以存储这个用户的偏好设置。然后不同的主题下给body元素添加不同的class,具体如下

 function enableDarkMode() {
   document.body.classList.add("dark-mode")
    localStorage.setItem('theme', 'dark');
  }

  function disableDarkMode() {
    document.body.classList.remove("dark-mode")
    localStorage.setItem('theme', 'light');
  }

和媒体查询一样,在dark-mode的情况下更改css变量的属性值,具体如下:

.dark-mode {
  --primary-bg: #282c35;
  --primary-fg: #fff;
  --secondary-bg: #1e2129;
  --secondary-fg: #aaa;
  --primary-btn-bg: #ddd;
  --primary-btn-fg: #222;
  --secondary-btn-bg: #780404;
  --secondary-btn-fg: #baba6a;
  --image-opacity: 0.85;
}

同时在进入这个页面的时候需要获取到用户的偏好设置,从localStorage中读取

let darkMode = localStorage.getItem("theme")

if (darkMode === "dark") enableDarkMode()

这次就可以在页面刷新以后仍然拿到用户的偏好设置。
但是这种方案仍然存在一定的问题,就是我们期望用户没有选择模式的时候,页面的模式能够跟随用户本身系统的设置而更改

最终方案

window上有个方法叫matchMedia,我们可以通过它获取当前用户系统处于什么模式,具体代码如下:

window
  .matchMedia("(prefers-color-scheme: dark)")
  .addListener(e => (e.matches ? enableDarkMode() : disableDarkMode()))

这样就能保证用户在没有设置偏好的时候使用默认的系统主题,完整代码如下:

const toggleButton = document.querySelector("#dark-mode-toggle")
  let darkMode = localStorage.getItem("theme")

  if (darkMode === "dark") enableDarkMode()

  toggleButton.addEventListener("click", e => {
    darkMode = localStorage.getItem("theme")
    if (darkMode === "dark") {
      disableDarkMode()
    } else {
      enableDarkMode()
    }
  })

  function enableDarkMode() {
    document.body.classList.add("dark-mode")
    localStorage.setItem("theme", "dark")
  }

  function disableDarkMode() {
    document.body.classList.remove("dark-mode")
    localStorage.setItem("theme", "light")
  }
  window
  .matchMedia("(prefers-color-scheme: dark)")
  .addListener(e => (e.matches ? enableDarkMode() : disableDarkMode()))
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。