Skip to content

网页实现跟随系统主题变色,附纯CSS解决方案和传统解决方案

页面跟随系统主题切换暗黑模式之前一直是用js实现的,虽然也并不是非常复杂,但是系统的监听总归不是非常优雅。

传统解决方案

js
/**
 * 根据用户的系统偏好设置,更新页面的主题样式(暗色/亮色模式)
 */
function updateDarkModeTheme() {
    // 检查用户是否启用了暗色模式(操作系统级别的偏好设置)
    const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;

    // 使用 classList.toggle 方法切换 'dark-mode' 类:
    // 如果 isDarkMode 为 true,则添加该类;
    // 否则,移除该类。
    document.body.classList.toggle('dark-mode', isDarkMode);
}

// 页面加载时立即应用一次用户的主题偏好
updateDarkModeTheme();

// 创建一个媒体查询对象,用于监听系统颜色方案的变化
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

// 推荐使用现代标准的 addEventListener 方式监听变化(适用于大多数现代浏览器)
if (typeof mediaQuery.addEventListener === 'function') {
    mediaQuery.addEventListener('change', updateDarkModeTheme);
} else {
    // 对于不支持 addEventListener 的旧浏览器(如 Safari 13 及更早版本)
    // 回退使用旧的监听方式:addListener
    mediaQuery.addListener(updateDarkModeTheme);
}

一直以来我都是用的这种解决方案,但是这种解决方案也有一些弊端。

  • 完全响应系统主题,用户无法通过页面上的按钮或其他方式主动选择亮色/暗色模式。
  • 首次加载时可能存在“闪屏”
  • 当用户更改系统主题时,网页立即切换样式,没有过渡效果。

最新解决方案

CSS在2024年上了一个新的API —— light-dark()

简单的说这个函数接受两个参数,一个是浅色模式下的色值,一个是暗黑模式下的色值。

css
:root {
    --color: light-dark('#333', '#ddd');
    --background-color: light-dark('#fff', '#eee');
}

但是需要注意,毕竟是新的API,老旧浏览器肯定是不支持。兼容性请查看下方的表格,新版浏览器一般都没啥问题。