+ + +
+ +
+
+
+
+ +
+
+
+ +
+ 15 +
+ + + + + + + + + + + + + + + + +
+ +
+ + + +
+ +
+ +

I am trying to add this dark mode feature in my app. It uses localstorage to store the user's preference for future usage. So the problem now is when the dark mode is enabled, and the page is reloaded for some reason, eg. if the user deliberately reloads the page, or submits a form, then there's a flicker of white background all over the page before it turns to be dark. It stays a fraction of a second. It just doesn't look professional.

+

Haven't found any solution yet. So please help me out.

+

PS. The snippet below won't work here in SO as the code includes localStorage object.

+

Here's the code:

+

+
+
const toggleSwitch = document.querySelector('#dark-mode-button input[type="checkbox"]');
+const currentTheme = localStorage.getItem('theme');
+
+if (currentTheme) {
+    document.documentElement.setAttribute('data-theme', currentTheme);
+    if (currentTheme === 'dark') {
+            toggleSwitch.checked = true;
+    }
+}
+
+function switchTheme(e) {
+    if (e.target.checked) {
+        document.documentElement.setAttribute('data-theme', 'dark');
+        localStorage.setItem('theme', 'dark');
+    }else {        
+        document.documentElement.setAttribute('data-theme', 'light');
+        localStorage.setItem('theme', 'light');
+    }    
+}
+
+toggleSwitch.addEventListener('change', switchTheme, false);  
+
:root {
+  --primary-color: #495057;
+  --bg-color-primary: #F5F5F5;
+}
+
+body{
+  background-color: var(--bg-color-primary); 
+}
+
+[data-theme="dark"] {
+  --primary-color: #8899A6;
+  --bg-color-primary: #15202B;
+}
+
+table {
+  font-family: arial, sans-serif;
+  border-collapse: collapse;
+  width: 100%;
+  background-color: #fff;
+}
+
+td, th {
+  border: 1px solid #dddddd;
+  text-align: left;
+  padding: 8px;
+}
+
<div id="dark-mode-button">
+    <input id="chck" type="checkbox">Dark Mode
+    <label for="chck" class="check-trail">
+      <span class="check-handler"></span>
+    </label>
+</div>
+
+<table class="table">
+    <thead>
+      <tr>
+          <th>Header 1</th>
+          <th>Header 2</th>
+          <th>Header 3</th>
+      </tr>
+    </thead>  
+    <tbody>
+      <tr>
+        <td>Alfreds Futterkiste</td>
+        <td>Maria Anders</td>
+        <td>Germany</td>
+      </tr>
+    </tbody>                     
+</table>
+
+
+

+
+ +
+ +
+ +
+
+
+ + + +
+ +
+ +
+ +
+ + + + +
+ +
+ + + + + + +
+
+
+
+ +
+ +
+
+ + + +
+
+
+ +
+ + + + + 8 +
+
+
    + +
  • +
    +
    + 3 +
    +
    +
    +
    + + Its most likely because the JS hasnt loaded and executed the check yet. So the page loads in normal mode, JS initialises, sets the dark mode and then it changes. + +
    +– Emre Koc +
    + Jul 22, 2020 at 11:47 +
    +
    +
  • +
  • +
    +
    + 1 +
    +
    +
    +
    + + What @EmreKoc says is correct. I would recommend putting the theme detection script as one of the first things on your page. Other than that, don't reload the whole page on navigation - just replace the part that's changed with ajax requests. + +
    +– MauriceNino +
    + Jul 22, 2020 at 11:49 +
    +
    +
  • +
  • +
    +
    +
    +
    +
    +
    + + Guys, sorry but can you please tell me which part of the code I should separate and where should I put that ? + +
    +– Zak +
    + Jul 22, 2020 at 11:51 +
    +
    +
  • +
  • +
    +
    + 3 +
    +
    +
    +
    + + Move the part of the code that sets the dark-light mode in a render-blocking fashion - meaning, inside the <head> of your document. Place the remaining scripts as usual, right before the closing </body> tag. That way, the browser will stop to interpret your JS inside head and will assign the needed data-theme attribute to your <html> tag. + +
    +– Roko C. Buljan +
    + Jul 22, 2020 at 11:59 + + + +
    +
    +
  • +
  • +
    +
    + 2 +
    +
    +
    +
    + + @RokoC.Buljan is correct. But, consider your querySelector you may need event delegation if you are to prioritize the loading of this script + + + Jul 22, 2020 at 12:06 +
    +
    +
  • + +
+
+ + +
+
+ +
+ + +
+
+
+
+ + + +
+ +
+
+
+

+ 1 Answer + 1 +

+
+
+ + +
+
+ + + Reset to default + +
+
+ +
+
+ + +
+
+ +
+ + + + +
+
+
+
+ +
+ 15 +
+ + + + + + + + + + + + +
+
+ +
+
+ + + + +
+ +
+ + + +
+ +
+

It would be ideal to block the page rendering by placing a small <script> tag inside the <head> of your Document. By doing so the DOM parser should stop and call the JavaScript interpreter, assign the data-theme attribute to <html> and than continue where left. Give it a try:

+

Place this <script> inside <head> - even before the <link> or <style> tags:

+
<head>
+  <!-- meta, title etc... -->
+
+  <script>
+  // Render blocking JS:
+  if (localStorage.theme) document.documentElement.setAttribute("data-theme", localStorage.theme);
+  </script>
+
+  <!-- link, style, etc... -->
+</head>
+
+

Then, right before the closing </body> tag use all the other scripts in a non-render-blocking manner:

+

+<!-- other <script> tags here -->
+
+<script>
+const toggleSwitch = document.querySelector('#dark-mode-button input[type="checkbox"]');
+
+if (localStorage.theme) {
+  toggleSwitch.checked = localStorage.theme === "dark";
+}
+
+function switchTheme(e) {
+  const theme = e.target.checked ? "dark" : "light";
+  document.documentElement.setAttribute("data-theme", theme);
+  localStorage.theme = theme;
+}
+
+toggleSwitch.addEventListener("change", switchTheme);
+</script>
+
+    
+<!-- Closing </body> goes here -->
+
+
+
+
+ +
+ + + +
+ +
+ +
+ +
+ + + + +
+ +
+ + + + + + +
+
+
+
+
+ +
+ + +
+ + + +
+
+ + +
+ +
+ + + + + 0 +
+
+
    + +
+
+ + +
+
+
+ +
+
+
+
+ + +
+ + + +

+ Your Answer +

+ + + + + + +
+ + +
+
+
+
+
+ +
+
+
+
+
+ + + + + +
+ + +
+ + +
+
+ +
+ + +
+ +
+ + +
+ + + + +
+ +
+ + +

+ By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct. +

+
+
+
+ + +

+
+Not the answer you're looking for? Browse other questions tagged or ask your own question.
+

+
+