如何解决页面重载时Dark Mode(暗黑模式)闪烁问题
问题原因分析
暗黑模式闪烁的核心原因是页面渲染顺序冲突:
- 当前你的暗黑模式脚本放在
<body>底部,浏览器会先渲染默认浅色样式,之后才执行脚本添加dark类切换暗黑模式,这就导致了短暂的浅色闪烁。 - 即使尝试把脚本移到HTML顶部,但如果放在CSS之后,浏览器仍会先加载并应用浅色CSS,再执行脚本切换类,依然会出现闪烁。
解决办法
要彻底解决闪烁,必须在浏览器开始渲染任何内容之前就设置好暗黑模式的类,确保CSS加载时就能直接应用对应的暗黑样式。具体步骤如下:
1. 将暗黑模式判断脚本移到<head>最顶部(所有CSS之前)
把暗黑模式逻辑放在<head>最开头,确保浏览器在加载任何CSS之前完成暗黑模式的状态判断和类设置。
2. 优化脚本逻辑,避免依赖DOMContentLoaded
设置dark类不需要等待DOM加载完成,直接操作document.documentElement即可;同时将toggle改为add/remove,避免状态异常。
修改后的完整代码示例
{% load static %} <!DOCTYPE html> <html lang="en"⚡> <head> <!-- 暗黑模式脚本:放在最顶部 --> <script> let darkMode = false; // 优先读取本地存储的用户偏好 const savedMode = localStorage.getItem("gmtNightMode"); if (savedMode === 'dark') { darkMode = true; } else if (savedMode === 'light') { darkMode = false; } else { // 本地存储无数据时,跟随系统设置 darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; } // 直接设置类,避免toggle导致的状态异常 if (darkMode) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } </script> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <!-- Favicon --> <link href="{% static 'images/logot.png' %}" rel="icon" type="image/png"> <link href="https://fonts.googleapis.com/css2?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="https://unpkg.com/@trevoreyre/autocomplete-js/dist/style.css"/> <!--AMP--> <!-- Basic Page Needs ================================================== --> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- icons ================================================== --> <link rel="stylesheet" href="{% static 'css/icons.css' %}"> <!-- CSS ================================================== --> <link rel="stylesheet" href="{% static 'css/uikit.css' %}"> <link rel="stylesheet" href="{% static 'css/style.css' %}"> <link rel="stylesheet" href="{% static 'css/tailwind.css' %}"> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <link rel="stylesheet" href="{% static 'cropperjs/dist/cropper.min.css' %}"> </head> <body> {% if request.user.is_authenticated %} <div class="container" id="id_loading_spinner" style="display: none"> <div class="d-flex flex-row mx-auto flex-grow-1 justify-content-center"> <div class="spinner-border text-primary" role="status"> <span class="sr-only">Loading...</span> </div> </div> </div> <div id="wrapper" class="is-collapse"> {% include 'snippets/base_css.html' %} {% include 'snippets/base_js.html' %} {% include 'snippets/header.html' %} {% include 'snippets/sidebar.html' %} {% block content %} {% endblock %} </div> {% else %} <div class="lg:p-12 max-w-xl lg:my-0 my-12 mx-auto p-6 space-y-"> <a href="{% url 'account:login' %}">Please login from here<h1 class="lg:text-2xl text-xl font-semibold mb-6"> Login </h1></a> </div> {% endif %} <!-- Javascript ================================================== --> <script> function displayLoadingSpinner(isDisplayed){ var spinner = document.getElementById("id_loading_spinner") if(isDisplayed){ spinner.style.display = "block" } else{ spinner.style.display = "none" } } </script> <!-- 暗黑模式切换事件:保留在底部 --> <script > document.addEventListener('DOMContentLoaded', () => { document.getElementById("night-mode").addEventListener('click', () => { const isDark = document.documentElement.classList.toggle('dark'); localStorage.setItem("gmtNightMode", isDark ? 'dark' : 'light'); }); }); </script>
额外优化建议
- 确保CSS中暗黑模式样式通过
.dark前缀正确定义,比如:body { background: #fff; } .dark body { background: #1a1a1a; } - 给
<html>标签添加过渡动画,让状态切换更平滑:html { transition: background-color 0.2s ease; }
内容的提问来源于stack exchange,提问作者Godda
相关产品推荐
相关产品推荐

