0

I got a little webpage, which you can find here: http://gabrielaelona18.esy.es/

With a CMS the user can replace the "theme-color". So a little script replaces every color with the hex code #16a085, no matter if background-color, border-bottom-color or whatever. That's the code:

$(function(){
        $('html').addClass('notransition');
        function colorReplace(findHexColor, replaceWith) {
          // Convert rgb color strings to hex
          function rgb2hex(rgb) {
            if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;
            rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
            function hex(x) {
              return ("0" + parseInt(x).toString(16)).slice(-2);
            }
            return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
          }

          // Select and run a map function on every tag
          $('*').map(function(i, el) {
            // Get the computed styles of each tag
            var styles = window.getComputedStyle(el);

            // Go through each computed style and search for "color"
            Object.keys(styles).reduce(function(acc, k) {
              var name = styles[k];
              var value = styles.getPropertyValue(name);
              if (value !== null && name.indexOf("color") >= 0) {
                // Convert the rgb color to hex and compare with the target color
                if (value.indexOf("rgb(") >= 0 && rgb2hex(value) === findHexColor) {
                  // Replace the color on this found color attribute
                  $(el).css(name, replaceWith);
                }
              }
            });
          });
        }
        // Call like this for each color attribute you want to replace
        colorReplace("#16a085", "#456780");
});

The thing is, that sometimes it works, but sometimes it just doesn't. You can visit the website, which I mentioned above. If its not blue, just reload a couple times, until you can see blue.

Tobias Glaus
  • 3,008
  • 3
  • 18
  • 37
  • Can’t reproduce the problem on your given example page. Wondering though why this is done via JS - if it gets set in the CMS, then why isn’t the CMS already outputting the code to make stuff appear in the configured colors ...? – CBroe Apr 13 '17 at 10:06
  • I haven't setup the CMS yet, but that's the goal. I'm just doing it with JS atm – Tobias Glaus Apr 13 '17 at 11:37

2 Answers2

2

You are having a network (page load) problem. Go check out your website loading with (Firefox) Developer Toolbar on the tab Network.

There you can see the following coincidences:

enter image description here enter image description here

The blue line shows the point in time where the document triggers an event, that the whole content of the page is loaded. (Specifics here.) This is called the DOMContentLoaded Event. See here for further details. As described in the linked page:

The DOMContentLoaded event is fired when the [...] document has been completely loaded and parsed, without waiting for stylesheets [...] to finish loading.

So this means, if the stylesheet makes it in time, the function you presented can manage to override the colors. If not, the function does not even find the corresponding color codes, because they are not there yet. Pretty simple.

This in turn means, that you should wait for your stylesheet to load before the function call. From the jQuery documentation, even $(document).ready() might not be enough, and instead you will have to use $(window).on("load", function() { ... }) to secure everything is ready. To have a clue about the load event, it is marked as the red line in the network monitor.

If this, for any reason, is not working out for you, you could of course move your color styles from the .css file into the html document as a style tag. Then, I guess, it will be available on DOMContentLoaded.

K. Rohde
  • 9,439
  • 1
  • 31
  • 51
  • Oh, I should really start using this firefox network toolbar more often. This would have saved me so much time. Thanks for this detailed answer! `.on("load"...` worked fine for me :) – Tobias Glaus Apr 13 '17 at 11:44
1

It looks like a timing issue to me.

I see the the green screen consistently when I have chrome dev-tools open, and I see a blue screen when I close it.

If I place a breakpoint at the top of your script, a$(function() at the top of your script, and once the CSS has been loaded continue, it will work as expected again.

So in order to fix your problem, you should only run colorReplace("#16a085", "#456780"); when your stylesheets have been parsed.

EDIT:

Acording to this article simply putting the stylesheets above your javascript might do the trick for you.

According to HTML5, DOMContentLoaded is a plain DOM ready event without taking stylesheets into account. However, the HTML5 parsing algorithm require browsers to defer the execution of scripts until all previous stylesheets are loaded. Let’s get back to the example from testcase #2:

<link rel="stylesheet" href="http://molily.de/weblog/stylesheet.css"> <script src="http://molily.de/weblog/script.js"></script> When the HTML5 parser encounters the ... tags, the whole parsing process is halted. First, the browser fetches the script resource, given it’s an external script. Second, the browser waits for the preceding stylesheet to load. Third, the JavaScript engine runs the downloaded script code. Finally, the parser continues to parse the HTML document.

EDIT 2

This answer looks like it confirms the solution in my first edit:

is-document-ready-also-css-ready?

Community
  • 1
  • 1
JasperZelf
  • 2,731
  • 1
  • 22
  • 34
  • I would say on document `load`, rather than `ready`, would have the best chance of success. – Niet the Dark Absol Apr 13 '17 at 10:22
  • Thanks for your detailed answer. Putting the CSS above the javascript is a good tip aswell. I'd love to accept both answers, but unfortunately I can't do that. I hope you understand if I accept the other one, since it's a bit better illustrated with the Firefox dev tools. You get a big upvote tho ;) – Tobias Glaus Apr 13 '17 at 11:56