Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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, same 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>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
429 views
Welcome To Ask or Share your Answers For Others

1 Answer

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 renderer should stop to 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>

Than, 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 -->

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...