为黑暗模式添加媒体查询

随着黑暗模式(Dark Mode)在现代操作系统和浏览器中的普及,为网站添加黑暗模式支持已成为提升用户体验的重要环节。本文将详细介绍如何使用CSS/SCSS媒体查询规范地实现黑暗模式,并提供正反面的代码示例。

1. 基础媒体查询语法

正确示例

scss 复制代码
// 使用prefers-color-scheme媒体查询
@media (prefers-color-scheme: dark) {
  body {
    background-color: #121212;
    color: #e0e0e0;
  }
  
  a {
    color: #bb86fc;
  }
}

@media (prefers-color-scheme: light) {
  body {
    background-color: #ffffff;
    color: #333333;
  }
  
  a {
    color: #6200ee;
  }
}

错误示例

scss 复制代码
// 错误:使用不规范的媒体查询条件
@media screen and (dark-mode: enabled) {
  /* 这种写法不被标准支持 */
}

// 错误:直接覆盖而不考虑用户偏好
body {
  background-color: #121212; /* 强制使用暗色,不考虑用户偏好 */
}

2. SCSS中的最佳实践

正确示例

scss 复制代码
// 定义颜色变量
$light-bg: #ffffff;
$light-text: #333333;
$light-link: #6200ee;

$dark-bg: #121212;
$dark-text: #e0e0e0;
$dark-link: #bb86fc;

// 基础样式(默认/回退样式)
body {
  background-color: $light-bg;
  color: $light-text;
  
  a {
    color: $light-link;
  }
}

// 黑暗模式覆盖
@media (prefers-color-scheme: dark) {
  body {
    background-color: $dark-bg;
    color: $dark-text;
    
    a {
      color: $dark-link;
    }
  }
}

错误示例

scss 复制代码
// 错误:变量命名不清晰
$color1: #fff;
$color2: #000;

// 错误:嵌套过深导致难以维护
@media (prefers-color-scheme: dark) {
  body {
    div {
      section {
        /* 过于复杂的嵌套 */
      }
    }
  }
}

3. 处理图片和SVG

正确示例

scss 复制代码
.logo {
  // 默认浅色模式logo
  background-image: url('logo-light.svg');
  
  @media (prefers-color-scheme: dark) {
    // 黑暗模式使用反色logo
    background-image: url('logo-dark.svg');
  }
}

// 或者使用CSS滤镜
.dark-image {
  @media (prefers-color-scheme: dark) {
    filter: invert(1) hue-rotate(180deg);
  }
}

错误示例

scss 复制代码
// 错误:硬编码图片路径,难以维护
@media (prefers-color-scheme: dark) {
  .header {
    background-image: url('/images/backgrounds/dark/header-bg.jpg');
    /* 路径结构过于具体,难以修改 */
  }
}

// 错误:过度使用滤镜影响性能
@media (prefers-color-scheme: dark) {
  * {
    filter: invert(1); /* 全局应用滤镜会严重影响性能 */
  }
}

4. 与自定义主题切换结合

正确示例

scss 复制代码
// 首先检查是否有本地存储的主题偏好
body {
  // 默认主题
  --bg-color: #ffffff;
  --text-color: #333333;
  --accent-color: #6200ee;
  
  background-color: var(--bg-color);
  color: var(--text-color);
  
  // 然后检查系统偏好
  @media (prefers-color-scheme: dark) {
    --bg-color: #121212;
    --text-color: #e0e0e0;
    --accent-color: #bb86fc;
  }
  
  // 用户手动选择黑暗模式
  &.dark-theme {
    --bg-color: #121212;
    --text-color: #e0e0e0;
    --accent-color: #bb86fc;
  }
  
  // 用户手动选择浅色模式
  &.light-theme {
    --bg-color: #ffffff;
    --text-color: #333333;
    --accent-color: #6200ee;
  }
}

错误示例

scss 复制代码
// 错误:媒体查询和类选择器优先级混乱
@media (prefers-color-scheme: dark) {
  body.dark-theme {
    /* 这种组合可能导致意外行为 */
  }
}

// 错误:过度使用!important
body.dark-theme {
  background-color: #121212 !important; /* 避免使用!important */
}

5. 过渡动画增强体验

正确示例

scss 复制代码
// 添加平滑的颜色过渡
body {
  transition: background-color 0.3s ease, color 0.3s ease;
  
  a {
    transition: color 0.3s ease;
  }
}

// 注意:在初始加载时禁用过渡以避免闪烁
body.no-transition,
body.no-transition * {
  transition: none !important;
}

错误示例

scss 复制代码
// 错误:过渡时间过长
body {
  transition: all 2s ease; /* 2秒过渡时间太长 */
}

// 错误:过渡属性过于宽泛
* {
  transition: all 0.3s ease; /* 影响所有属性,性能不佳 */
}

6. 测试和回退策略

正确示例

scss 复制代码
// 使用@supports检查媒体查询支持
@supports not (prefers-color-scheme: dark) {
  // 为不支持媒体查询的浏览器提供回退
  body {
    background-color: $light-bg;
    color: $light-text;
  }
}

// 或者使用JavaScript检测并添加回退类
// <script>
// if (!window.matchMedia('(prefers-color-scheme)').matches) {
//   document.body.classList.add('no-prefers-color-scheme');
// }
// </script>

错误示例

scss 复制代码
// 错误:假设所有浏览器都支持
@media (prefers-color-scheme: dark) {
  /* 没有考虑不支持的情况 */
}

// 错误:复杂的浏览器嗅探
@-moz-document url-prefix() {
  /* 特定浏览器hack,不推荐 */
}

结论

实现黑暗模式时,应遵循以下规范:

  1. 使用标准的prefers-color-scheme媒体查询
  2. 在SCSS中合理组织变量和嵌套
  3. 提供适当的过渡动画增强用户体验
  4. 考虑与自定义主题切换的兼容性
  5. 为不支持媒体查询的浏览器提供回退方案
  6. 避免性能陷阱和过于复杂的嵌套

通过遵循这些规范,可以创建出既美观又易于维护的黑暗模式实现,为用户提供更加舒适和个性化的浏览体验。