admin管理员组

文章数量:1325726

I'm currently working on a theme toggle for my website that uses Javascript / jQuery to manipulate the Body.bg color using a lightmode()/ darkmode() function that is toggled by a button. What I want to do is create seamless transitioning between the body bg color with fade in and fade outs. I already have that made and created, but the problem is when the theme reads the storage type it will blink quickly in Chrome and Chrome Canary but in Safari, and Safari Tech Preview for Catalina it works seamlessly.

However, I keep running into an issue when the user switches to white and then clicks on the nav link which then causes a black blink of the dark mode theme. My site starts with dark mode enabled and body bg is = #0a0a0a, but when it switches to white and the storage is updated, it still inherits the black body - bg that is initially set in the style.less of my theme.

If I remove the background color, then the white flicker happens on the dark mode theme, and ideally my end goal is to create seamless page navigation without the page blinking for a quick second reading the initial bg color before the body loads so - white on white bg, black on black bg no blinking to cause visual disruption.

I've tried every work around I could e up with and can't figure out a solution. It works in Safari with no page blinking, but in Chrome it still blinks. I've included video links showing what I want to acplish with the Safari render for Google chrome and the main.js code file.

Safari - seamless transitioning

Chrome and Chrome Canary - watch for the blink on white transition. It's quick but super frustrating.

So what's going on?! The problem is the theme is now set to white, but the initial body - bg color is black in the style.less theme and it picks that up real quick before snapping back to the white theme.

When I audit the site in Canary, and run it at slow 3G simulated there is no blink, but when it ran normally or at Fast 3G in the audit the blink occurs. My hypothesis is to set a timeout on the body before loading it, but I tried that as a work around and still got blinking.

I've tried to create key stored in local storage for my storage and to also pause the body from loading, but so far I can't find a solution to this :/

So what I want to do is to stop the body bg color from flickering white or black based off the theme colors base color without blinking.

Thanks for taking the time to read my problem!

document.addEventListener("DOMContentLoaded", function() {
document.body.style.backgroundColor = "inherit";

if (document.readyState === 'plete') {

if(lightmodeON == true) {
  $('body').css({background: "#FFF"});
  console.log('loading white bg');
}

if(lightmodeON == false) {
  $('body').css({background: "#0a0a0a"});
  console.log('loading black bg');
}
}


if (typeof (Storage) !=="undefined") {
if (localStorage.themepref == 1 ) {
  lightmode();
}
else {
  darkmode();
  localStorage.themepref = 2;
}

if(lightmodeON == true) {
  $('body').css({background: "#FFF"});
  console.log('loading fffwhite bg');
}

if(lightmodeON == false) {
  $('body').css({background: "#0a0a0a"});
  console.log('loading black bg');
}
}

Here is my version of trying to make a work around.

var clickDelay = false;
var themeType = -1;
var lightmodeON = false;


window.onload = function() {
  console.log('First');

  if (event.target.readyState === 'interactive') {

      $('body').css({ background: ''});
      document.body.style.backgroundColor = "inherit";

   if(lightmodeON == true) {
     $('body').css({background: "#FFF"});
       document.body.style.backgroundColor = "#FFF";
   }

   if(lightmodeON == false) {
     $('body').css({background: "#0a0a0a"});
       document.body.style.backgroundColor = "#0a0a0a";
   }
}
    overloadBG();
};


document.addEventListener("DOMContentLoaded", function() {
  document.body.style.backgroundColor = "inherit";

  if (document.readyState === 'plete') {

    if(lightmodeON == true) {
      $('body').css({background: "#FFF"});
      console.log('loading white bg');
    }

    if(lightmodeON == false) {
      $('body').css({background: "#0a0a0a"});
      console.log('loading black bg');
    }
  }


  if (typeof (Storage) !=="undefined") {
    if (localStorage.themepref == 1 ) {
      lightmode();
    }
    else {
      darkmode();
      localStorage.themepref = 2;
    }

    if(lightmodeON == true) {
      $('body').css({background: "#FFF"});
      console.log('loading fffwhite bg');
    }

    if(lightmodeON == false) {
      $('body').css({background: "#0a0a0a"});
      console.log('loading black bg');
    }
  }



});

window.addEventListener('beforeunload', function (e) {
  $('body').css({ background: ''});

  if(lightmodeON == true) {
    $('body').css({background: "#FFF"});
      document.body.style.backgroundColor = "#FFF";
  }

  if(lightmodeON == false) {
    $('body').css({background: "#0a0a0a"});
      document.body.style.backgroundColor = "#0a0a0a";
  }

  document.body.style.backgroundColor = "inherit";
  overloadBG();
  
});

window.onbeforeunload = function () {
  //FUCK YOU BLINK
  //$('body').css({ background: 'none'});
  $('body').css({ background: ''});
    document.body.style.backgroundColor = "";

  if (typeof (Storage) !=="undefined") {
    if (localStorage.themepref == 1 ) {
        localStorage.themepref = 1;
        lightmode();
    }
    else {
      darkmode();
      localStorage.themepref = 2;
    }
  }

}

document.onreadystatechange = function() {


    $('body').css({ background: ''});
    document.body.style.backgroundColor = "transparent";

    if (event.target.readyState === 'interactive') {
        console.log('interactive');

             if(lightmodeON === true) {
               $('body').css({background: "#FFF"});
             }

             if(lightmodeON === false) {
               $('body').css({background: "#0a0a0a"});
             }
      }

      if (event.target.readyState === 'loading') {

          $('body').css({ background: ''});

       if(lightmodeON == true) {
         $('body').css({background: "#FFF"});
         $("body").css("cssText", "background: #FFF !important;");
       }

       if(lightmodeON == false) {
         $('body').css({background: "#0a0a0a"});
         $("body").css("cssText", "background: #0a0a0a !important;");
       }
    }

I'm currently working on a theme toggle for my website that uses Javascript / jQuery to manipulate the Body.bg color using a lightmode()/ darkmode() function that is toggled by a button. What I want to do is create seamless transitioning between the body bg color with fade in and fade outs. I already have that made and created, but the problem is when the theme reads the storage type it will blink quickly in Chrome and Chrome Canary but in Safari, and Safari Tech Preview for Catalina it works seamlessly.

However, I keep running into an issue when the user switches to white and then clicks on the nav link which then causes a black blink of the dark mode theme. My site starts with dark mode enabled and body bg is = #0a0a0a, but when it switches to white and the storage is updated, it still inherits the black body - bg that is initially set in the style.less of my theme.

If I remove the background color, then the white flicker happens on the dark mode theme, and ideally my end goal is to create seamless page navigation without the page blinking for a quick second reading the initial bg color before the body loads so - white on white bg, black on black bg no blinking to cause visual disruption.

I've tried every work around I could e up with and can't figure out a solution. It works in Safari with no page blinking, but in Chrome it still blinks. I've included video links showing what I want to acplish with the Safari render for Google chrome and the main.js code file.

Safari - seamless transitioning

Chrome and Chrome Canary - watch for the blink on white transition. It's quick but super frustrating.

So what's going on?! The problem is the theme is now set to white, but the initial body - bg color is black in the style.less theme and it picks that up real quick before snapping back to the white theme.

When I audit the site in Canary, and run it at slow 3G simulated there is no blink, but when it ran normally or at Fast 3G in the audit the blink occurs. My hypothesis is to set a timeout on the body before loading it, but I tried that as a work around and still got blinking.

I've tried to create key stored in local storage for my storage and to also pause the body from loading, but so far I can't find a solution to this :/

So what I want to do is to stop the body bg color from flickering white or black based off the theme colors base color without blinking.

Thanks for taking the time to read my problem!

document.addEventListener("DOMContentLoaded", function() {
document.body.style.backgroundColor = "inherit";

if (document.readyState === 'plete') {

if(lightmodeON == true) {
  $('body').css({background: "#FFF"});
  console.log('loading white bg');
}

if(lightmodeON == false) {
  $('body').css({background: "#0a0a0a"});
  console.log('loading black bg');
}
}


if (typeof (Storage) !=="undefined") {
if (localStorage.themepref == 1 ) {
  lightmode();
}
else {
  darkmode();
  localStorage.themepref = 2;
}

if(lightmodeON == true) {
  $('body').css({background: "#FFF"});
  console.log('loading fffwhite bg');
}

if(lightmodeON == false) {
  $('body').css({background: "#0a0a0a"});
  console.log('loading black bg');
}
}

Here is my version of trying to make a work around.

var clickDelay = false;
var themeType = -1;
var lightmodeON = false;


window.onload = function() {
  console.log('First');

  if (event.target.readyState === 'interactive') {

      $('body').css({ background: ''});
      document.body.style.backgroundColor = "inherit";

   if(lightmodeON == true) {
     $('body').css({background: "#FFF"});
       document.body.style.backgroundColor = "#FFF";
   }

   if(lightmodeON == false) {
     $('body').css({background: "#0a0a0a"});
       document.body.style.backgroundColor = "#0a0a0a";
   }
}
    overloadBG();
};


document.addEventListener("DOMContentLoaded", function() {
  document.body.style.backgroundColor = "inherit";

  if (document.readyState === 'plete') {

    if(lightmodeON == true) {
      $('body').css({background: "#FFF"});
      console.log('loading white bg');
    }

    if(lightmodeON == false) {
      $('body').css({background: "#0a0a0a"});
      console.log('loading black bg');
    }
  }


  if (typeof (Storage) !=="undefined") {
    if (localStorage.themepref == 1 ) {
      lightmode();
    }
    else {
      darkmode();
      localStorage.themepref = 2;
    }

    if(lightmodeON == true) {
      $('body').css({background: "#FFF"});
      console.log('loading fffwhite bg');
    }

    if(lightmodeON == false) {
      $('body').css({background: "#0a0a0a"});
      console.log('loading black bg');
    }
  }



});

window.addEventListener('beforeunload', function (e) {
  $('body').css({ background: ''});

  if(lightmodeON == true) {
    $('body').css({background: "#FFF"});
      document.body.style.backgroundColor = "#FFF";
  }

  if(lightmodeON == false) {
    $('body').css({background: "#0a0a0a"});
      document.body.style.backgroundColor = "#0a0a0a";
  }

  document.body.style.backgroundColor = "inherit";
  overloadBG();
  
});

window.onbeforeunload = function () {
  //FUCK YOU BLINK
  //$('body').css({ background: 'none'});
  $('body').css({ background: ''});
    document.body.style.backgroundColor = "";

  if (typeof (Storage) !=="undefined") {
    if (localStorage.themepref == 1 ) {
        localStorage.themepref = 1;
        lightmode();
    }
    else {
      darkmode();
      localStorage.themepref = 2;
    }
  }

}

document.onreadystatechange = function() {


    $('body').css({ background: ''});
    document.body.style.backgroundColor = "transparent";

    if (event.target.readyState === 'interactive') {
        console.log('interactive');

             if(lightmodeON === true) {
               $('body').css({background: "#FFF"});
             }

             if(lightmodeON === false) {
               $('body').css({background: "#0a0a0a"});
             }
      }

      if (event.target.readyState === 'loading') {

          $('body').css({ background: ''});

       if(lightmodeON == true) {
         $('body').css({background: "#FFF"});
         $("body").css("cssText", "background: #FFF !important;");
       }

       if(lightmodeON == false) {
         $('body').css({background: "#0a0a0a"});
         $("body").css("cssText", "background: #0a0a0a !important;");
       }
    }

Share Improve this question edited Aug 28, 2019 at 21:40 Monstr92 asked Aug 27, 2019 at 0:07 Monstr92Monstr92 4049 silver badges26 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5 +100

By the time DOMContentLoaded will fire, the browser may already have painted your page's background.

Here is a demo which does reload the page indefinitely, be sure to click "hide results" when you're done watching it, it may make your puter use some CPU resources (but no network ones).

/* 
  We use an iframe to avoid making real network requests 
  Below is the HTML content of this iframe
*/

const content = `<!DOCTYPE html>
<html>
  <head>
    <style>
      /* default bg color */
      body { background: red; }
    </style>
    <script>
      document.addEventListener('DOMContentLoaded', e => {
        document.body.style.backgroundColor = 'green';
        location.reload() // infinite reload...
      });
    <\/script>
  </head>
  <body>
    <div>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi blandit cursus orci ut maximus. Phasellus pharetra lobortis pellentesque. Pellentesque et lacus et lorem facilisis ultrices. Maecenas sed ultricies nisi. Suspendisse feugiat finibus justo, id consectetur turpis aliquam ac. Proin sit amet laoreet velit. Nullam felis lectus, modo imperdiet mollis in, ullamcorper eget tortor. Nullam at metus non diam faucibus aliquam. Vestibulum eu maximus risus, vitae elementum justo. Fusce modo lacus a augue lobortis, quis ornare odio gravida. Quisque ultrices tempus tellus, vitae pulvinar est rutrum in. Duis ante erat, placerat sit amet imperdiet vitae, facilisis non mauris. Integer eu ex sapien.</p>
      <p>Morbi porttitor justo eu sodales efficitur. Integer ut suscipit libero, sed dapibus velit. Vestibulum laoreet neque ac odio consequat, a suscipit arcu tristique. Curabitur tempor, nisl eu porttitor feugiat, nibh lorem laoreet massa, ut porta tellus augue accumsan metus. Suspendisse sed venenatis neque. Aliquam non justo in tortor dictum suscipit. Duis eu lectus eu dui placerat luctus. Etiam et volutpat diam, nec ullamcorper tellus. Nullam nibh dui, bibendum a ipsum et, elementum tempor mi. Maecenas ut eros eu sem malesuada tincidunt. Aenean fermentum sit amet augue quis vulputate. Vivamus modo pellentesque purus rhoncus suscipit. Proin et enim vel ipsum vulputate mollis venenatis ut enim. Curabitur eget velit mollis, luctus sem at, aliquam est. Donec quis elit erat. Nullam facilisis lorem nisl, a luctus purus tristique vel.</p>
      <p>Donec in magna at ante mollis sodales ac vitae mauris. Aliquam condimentum ligula nulla, scelerisque cursus neque consequat quis. Fusce vestibulum nisi vitae ipsum venenatis, a pharetra diam tempus. Aenean maximus enim orci, quis mollis neque sollicitudin et. Quisque viverra ipsum vitae magna varius, id ornare justo dictum. Quisque eleifend magna ac congue dignissim. Duis eu volutpat quam, quis placerat tellus. Pellentesque felis mi, imperdiet eu semper vel, hendrerit sit amet ex.</p>
    </div>
  </body>
</html>
`;
frame.src = URL.createObjectURL(new Blob([content], {type: 'text/html'}));
<iframe id="frame" widht="500" height="500"></iframe>

To workaround this issue, move your scripts at the top of the <body> and set the initial <body> color from Storage as soon as possible.
You will still be able to wait for the Document is ready before attaching other events.

/* 
  We use an iframe to avoid making real network requests 
  Below is the HTML content of this iframe
*/

const content = `<!DOCTYPE html>
<html>
  <head>
    <style>
      /* default bg color */
      body { background: red; }
    </style>
  </head>
  <body>
    <!-- move inside <body> -->
    <script>
      // first retrieve from Storage
      // const lightModeOn = locaStorage.getItem('lightmode') === "1";
      // StackSnippets don't allow Storage...
      const lightModeOn = true;
      // set directly the body's style, we're in so we don't need to wait, it's already available
      document.body.style.backgroundColor = 'green';
      // then wait for DOMContentLoaded if you wish to add listeners to other events
      document.addEventListener('DOMContentLoaded', e => {
      // $('.toggle').on('input', switchLight);

      // just to demonstrate it works
      location.reload();
   });
      
    <\/script>

    <div>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi blandit cursus orci ut maximus. Phasellus pharetra lobortis pellentesque. Pellentesque et lacus et lorem facilisis ultrices. Maecenas sed ultricies nisi. Suspendisse feugiat finibus justo, id consectetur turpis aliquam ac. Proin sit amet laoreet velit. Nullam felis lectus, modo imperdiet mollis in, ullamcorper eget tortor. Nullam at metus non diam faucibus aliquam. Vestibulum eu maximus risus, vitae elementum justo. Fusce modo lacus a augue lobortis, quis ornare odio gravida. Quisque ultrices tempus tellus, vitae pulvinar est rutrum in. Duis ante erat, placerat sit amet imperdiet vitae, facilisis non mauris. Integer eu ex sapien.</p>
      <p>Morbi porttitor justo eu sodales efficitur. Integer ut suscipit libero, sed dapibus velit. Vestibulum laoreet neque ac odio consequat, a suscipit arcu tristique. Curabitur tempor, nisl eu porttitor feugiat, nibh lorem laoreet massa, ut porta tellus augue accumsan metus. Suspendisse sed venenatis neque. Aliquam non justo in tortor dictum suscipit. Duis eu lectus eu dui placerat luctus. Etiam et volutpat diam, nec ullamcorper tellus. Nullam nibh dui, bibendum a ipsum et, elementum tempor mi. Maecenas ut eros eu sem malesuada tincidunt. Aenean fermentum sit amet augue quis vulputate. Vivamus modo pellentesque purus rhoncus suscipit. Proin et enim vel ipsum vulputate mollis venenatis ut enim. Curabitur eget velit mollis, luctus sem at, aliquam est. Donec quis elit erat. Nullam facilisis lorem nisl, a luctus purus tristique vel.</p>
      <p>Donec in magna at ante mollis sodales ac vitae mauris. Aliquam condimentum ligula nulla, scelerisque cursus neque consequat quis. Fusce vestibulum nisi vitae ipsum venenatis, a pharetra diam tempus. Aenean maximus enim orci, quis mollis neque sollicitudin et. Quisque viverra ipsum vitae magna varius, id ornare justo dictum. Quisque eleifend magna ac congue dignissim. Duis eu volutpat quam, quis placerat tellus. Pellentesque felis mi, imperdiet eu semper vel, hendrerit sit amet ex.</p>
    </div>
  </body>
</html>
`;
frame.src = URL.createObjectURL(new Blob([content], {type: 'text/html'}));
<iframe id="frame" widht="500" height="500"></iframe>

<html>
<head>
    <title></title>
    <script src="https://code.jquery./jquery-1.10.2.js"></script>
</head>
<body>
<header>
    <nav class="menu">
        <label for="darkmode"><input type="radio" name="theme" value="1" id="darkmode" class="themechange" />Dark Mode</label>
        <label for="lightmode"><input type="radio" checked="checked" name="theme" value="0" class="themechange" id="lightmode" />Light Mode</label>
    </nav>
</header>
<div class="content">
    <p>CSS (Cascading Style Sheets) is a representation style sheet language used for describing the look and formatting of HTML (Hyper Text Markup Language), XML (Extensible Markup Language) documents and SVG elements including (but not limited to) colors, layout, fonts, and animations. It also describes how elements should be rendered on screen, on paper, in speech, or on other media.</p>
    <img src="https://farm8.staticflickr./7632/16990947835_3894284fd8_b.jpg">

    <p>CSS (Cascading Style Sheets) is a representation style sheet language used for describing the look and formatting of HTML (Hyper Text Markup Language), XML (Extensible Markup Language) documents and SVG elements including (but not limited to) colors, layout, fonts, and animations. It also describes how elements should be rendered on screen, on paper, in speech, or on other media.</p>


    <p>CSS (Cascading Style Sheets) is a representation style sheet language used for describing the look and formatting of HTML (Hyper Text Markup Language), XML (Extensible Markup Language) documents and SVG elements including (but not limited to) colors, layout, fonts, and animations. It also describes how elements should be rendered on screen, on paper, in speech, or on other media.</p>
</div>
<style>
nav{background:#ddd; height:40px;}
img{width:350px}
body{margin:0px; padding:0px; color:#111; transition:all 0.5s;}
body.dark{color:#fff; background:#000;}
body.dark nav{background:#cc0000;transition:all 0.5s;}
</style>




<script>
$(function(){
    $("#lightmode").click(function(){
            $("body").removeClass("dark");
    })
    $("#darkmode").click(function(){
            $("body").addClass("dark");
    })
})
</script>
</body>
</html>

Toggle the class name on the selection of theme and add transition:all 0.5s in css code to make transition smooth.

Here's what I would suggest for a quick solution: I would first remove the background-color property from the CSS all together from the element which causes this clashing property renderings.

Then, add a function to my JS file which checks the status of the visitor's setting according the theme and apply the background directly from JS.

if(lightmodeON == true) {
  $('body').css({background: "#FFF"});
  console.log('loading white bg');
}

if(lightmodeON == false) {
  $('body').css({background: "#0a0a0a"});
  console.log('loading black bg');
}
}

And maybe include a fallback within the PHP code (in the samples you posted on jsfiddle I saw that you're coding in PHP) in case the javascript is disabled/not supported in a visitor's browser and echo out the CSS code, after the tags, not before because browsers and DOM model acts as a cued sheet of mands, not like object oriented code and it'll always load from top to bottom. So the loading hierarchy will affect how things work, and sometimes may cause clashes with what you're trying to achieve:

<script src="yourScriptHere.js">
//Some parameters if needed (Such as state of theme preference retrieved from the session and passed into a variable). For the sake of this example:
var lightmodeON = <?php echo $_SESSION('themePreference');?>;
</script>
<style>/*Then your style here*/</style>
<!--OR-->
<link href="yourStyleSheets.css" rel="stylesheet" />

There is no reason to include the property in the CSS if it causes clashes with your pleted product. But always make sure to add a ment in the CSS file for you to see later that you've excluded that property and where you put it in order not to suffer in future edits like so:

body {
    /* background-color property is set in JS file and excluded from CSS */
    margin: 0;
    [...]
}

I'm assuming excluding things from CSS in this case won't hurt since it seems like you will be using the HTML/CSS/JS as a plete application package here to assure full functionality anyways.

Other than this, you can also try playing around with background-visibility property within the CSS file to the elements where the flickering occurs, as this sometimes weirdly helps solving some flickering problems.

I'd also remend you to create an Ajax call and store the theme preference setting in a session object so this way you pass and can access it through JS in other pages, and/or visitor es back to the site after closing the browser window.

I hope this helps. Cheers!

本文标签: