0

The site contains a light/dark mode switch. I know how to set the different theme for my site with JavaScript and CSS.

I make an AJAX call and as response it is a HTML string. This string is appended as child inside a DIV. The problem is that I have no control of what's inside this DIV. The content is generated through a CMS and it can be anything.

Is it possible to set the dark mode for this random content as well? How do I query every DOM element and change it's background color, text color? I've seen that you can calculate if a color is bright or dark from here

UPDATE fiddle with working solution:

<script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.3.4/lib/darkmode-js.min.js"></script>
 <p
    style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; margin-top: 1.5em; margin-bottom: 1.5em; font-size: 1.1875em; font-family: &quot;Mercury SSm A&quot;, &quot;Mercury SSm B&quot;, Georgia, Times, &quot;Times New Roman&quot;, &quot;Microsoft YaHei New&quot;, &quot;Microsoft Yahei&quot;, 微软雅黑, 宋体, SimSun, STXihei, 华文细黑, serif; line-height: 1.5; animation: 1000ms linear 0s 1 normal none running fadeInLorem; background-color: rgb(85, 98, 113);">
    <font color="#f7f5f5">Vel elit scelerisque mauris pellentesque pulvinar pellentesque habitant morbi. Metus
        aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices. Ultrices tincidunt arcu non sodales
        neque. Ipsum nunc aliquet bibendum enim facilisis gravida. Consequat ac felis donec et odio. Orci sagittis
        eu volutpat odio facilisis mauris. Sagittis nisl rhoncus mattis rhoncus. Vel elit scelerisque mauris
        pellentesque pulvinar pellentesque habitant morbi. Phasellus egestas tellus rutrum tellus pellentesque eu
        tincidunt. Non blandit massa enim nec dui nunc mattis enim. Amet nisl suscipit adipiscing bibendum est
        ultricies. Porttitor massa id neque aliquam vestibulum morbi blandit cursus risus. Donec et odio
        pellentesque diam volutpat commodo sed egestas egestas.</font>
</p>
<script>
    var options = {
        bottom: '64px', // default: '32px'
        right: 'unset', // default: '32px'
        left: '32px', // default: 'unset'
        time: '0.5s', // default: '0.3s'
        mixColor: '#fff', // default: '#fff'
        backgroundColor: '#fff',  // default: '#fff'
        buttonColorDark: '#100f2c',  // default: '#100f2c'
        buttonColorLight: '#fff', // default: '#fff'
        saveInCookies: false, // default: true,
        label: '' // default: ''
    }

    const darkmode = new Darkmode(options);
    darkmode.showWidget();
</script>

https://jsfiddle.net/3Lhwyogc/

Cristi Ghinea
  • 474
  • 1
  • 7
  • 20
  • 1
    An [mcve] is lacking so it's hard to tell, but sometimes a simple [`.dark { filter: invert(100%); }`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter) is enough to switch to a dark mode. – Nino Filiu Jul 06 '19 at 14:50

3 Answers3

1

Yes it is possible set the dark mode for any random content as well. You can read this well written blog to understand -> https://dev.to/wgao19/night-mode-with-mix-blend-mode-difference-23lm

You should check out Darkmode.js it is based on this concept and by gives you a widget to turn on and off the dark-mode.

Darkmode.js

You can simply add these line in your webpage and you will get a toggle button.

<script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.3.4/lib/darkmode-js.min.js"></script>
<script>

  var options = {
  bottom: '64px', // default: '32px'
  right: 'unset', // default: '32px'
  left: '32px', // default: 'unset'
  time: '0.5s', // default: '0.3s'
  mixColor: '#fff', // default: '#fff'
  backgroundColor: '#fff',  // default: '#fff'
  buttonColorDark: '#100f2c',  // default: '#100f2c'
  buttonColorLight: '#fff', // default: '#fff'
  saveInCookies: false, // default: true,
  label: '' // default: ''
}

const darkmode = new Darkmode(options);
darkmode.showWidget();

</script>
Aman Raj
  • 239
  • 3
  • 15
1

If that div is supposed to be part of your page, and you have control over what's in that page, then it's easy, just start predicting everything and add hundreds of lines of CSS:

.dark .item {
    background: black;
}
.light .item {
    background: white;
}

or you could ease your pain with SASS or LESS or something else.


But if your div could be anything including any boxes and unpredictable content that has their own style and you don't have full control of the styles and scripts that come from that ajax, then here are some ideas:

One way is to do something like this:

function lightOrDark(color) {

    // Variables for red, green, blue values
    var r, g, b, hsp;

    // Check the format of the color, HEX or RGB?
    if (color.match(/^rgb/)) {

        // If HEX --> store the red, green, blue values in separate variables
        color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);

        r = color[1];
        g = color[2];
        b = color[3];
    } 
    else {

        // If RGB --> Convert it to HEX: http://gist.github.com/983661
        color = +("0x" + color.slice(1).replace( 
        color.length < 5 && /./g, '$&$&'));

        r = color >> 16;
        g = color >> 8 & 255;
        b = color & 255;
    }

    // HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
    hsp = Math.sqrt(
    0.299 * (r * r) +
    0.587 * (g * g) +
    0.114 * (b * b)
    );

    // Using the HSP value, determine whether the color is light or dark
    if (hsp>127.5) {

        return 'light';
    } 
    else {

        return 'dark';
    }
}


function getStyle(el, styleProp) {
  var value, defaultView = (el.ownerDocument || document).defaultView;
  // W3C standard way:
  if (defaultView && defaultView.getComputedStyle) {
    // sanitize property name to css notation
    // (hypen separated words eg. font-Size)
    styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
    return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
  } else if (el.currentStyle) { // IE
    // sanitize property name to camelCase
    styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
      return letter.toUpperCase();
    });
    value = el.currentStyle[styleProp];
    // convert other units to pixels on IE
    if (/^\d+(em|pt|%|ex)?$/i.test(value)) { 
      return (function(value) {
        var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
        el.runtimeStyle.left = el.currentStyle.left;
        el.style.left = value || 0;
        value = el.style.pixelLeft + "px";
        el.style.left = oldLeft;
        el.runtimeStyle.left = oldRsLeft;
        return value;
      })(value);
    }
    return value;
  }
}






function switch_color(el) {
  const switchable_attrs = "color backgroundColor".split(' '); // add more properties here
  for (let i in switchable_attrs) {
    let attr = switchable_attrs[i];
    let color = getStyle(el, attr);
    console.info(attr, color, el);
    if (color == "")
        continue;
    try {
        el.style[attr] = colorsys.stringify(colorsys.darken(colorsys.parseCss(color), lightOrDark(color) == "dark" ? -0.5 : 0.5));
        console.info("Color changed from " + color + " to " + el.style[attr]);
    } catch(e) {
        console.warn("Cannot switch color: " + color, e, el);
    }
  }

  for (let i = 0; i < el.children.length; i++) {
    switch_color(el.children[i]);
  }
}

let div = document.getElementById('the-div');
switch_color(div);


source of getStyle function: https://stackoverflow.com/a/2664055/4987470

colorsys github: https://github.com/netbeast/colorsys

The code above will switch every color it finds. change the percentage of the darken function to add more contrast.

It may still need some tweaks for your environment.


For images and background images there are still ways to invert those that you can load in javascript (cross-origin problem). But I leave that for some other time and I'm sure people have already solved that problem.

The Moisrex
  • 1,857
  • 1
  • 14
  • 16
1

All the above answers is not right good ,, i will write here some code for bloggers to apply night mode on own blogs... check this on my blog Hindi Tutor working well.. 100% working, and dark mode is not going to off when you refresh the page..

<!-- Theme Functions JS -->
<script type='text/javascript'>
//<![CDATA[
function retheme() {
  var cc = document.body.className;
  if (cc.indexOf("darktheme") > -1) {
    document.body.className = cc.replace("darktheme", "");
    if (opener) {opener.document.body.className = cc.replace("darktheme", "");}
    localStorage.setItem("preferredmode", "light");
  } else {
    document.body.className += " darktheme";
    if (opener) {opener.document.body.className += " darktheme";}
    localStorage.setItem("preferredmode", "dark");
  }
}
(
function setThemeMode() {
  var x = localStorage.getItem("preferredmode");
  if (x == "dark") {
    document.body.className += " darktheme";
  }
})();
//]]>
</script>
<!-- theme switch is a button icon adjust this as your icon stylesheet -->
#theme-switch{font-size:20px;position:absolute;top:0;right:35px;z-index:19}
<!-- Here is your stylesheet for dark mode editd these colors and style name except body darktheme -->
body.darktheme{color:#fff;background-color:#000}
body.darktheme .your-element-name{color:#fff;background-color:#000}
body.darktheme .lin-element-name a{color:#fff;background-color:#000}
body.darktheme #your-element-name{color:#fff;background-color:#000}
body.darktheme your-element-name ul li a{color:#fff;background-color:#000}
<div id='theme-switch'>
<a class='fa fa-adjust' href='javascript:void(0);' onclick='retheme()' title='Change Theme'/>
    </div>