JavaScript: Invert color on all elements of a page

Muhd picture Muhd · Jan 22, 2011 · Viewed 50.1k times · Source

Note: I am keeping an up-to-date version of the bookmarklet in my question which works well and is based on Jacob's answer. If you are looking for a bookmarklet to use, use that one. See leosok's fantastic answer if you just want something amazing that works on chrome.

I want to be able to invert the color of all the elements on a page with a JavaScript bookmarklet. I know that to invert a color you subtract each of the RGB hex values from 255(xFF), but beyond that I am unsure of how to proceed.

How can I accomplish this?

Using jQuery is acceptable, and it only needs to work on Chrome, although if it worked in Firefox that'd be a plus.

This is excluding images - background, text and links colors should all be inverted. Basically anything that gets its color from CSS.

UPDATE Here is an updated bookmarklet that fixes the nested element issue and will work on a lot of different sites (including this one)

UPDATE2 Added some support for transparency, handling elements that have default background-color rgba(0, 0, 0, 0). More sites should be working now with the updated one.

javascript: (function ($) {
    function load_script(src, callback) {
        var s = document.createElement('script');
        s.src = src;
        s.onload = callback;
        document.getElementsByTagName('head')[0].appendChild(s);
    }

    function invertElement() {
        var colorProperties = ['color', 'background-color'];
        var color = null;
        for (var prop in colorProperties) {
            prop = colorProperties[prop];
            if (!$(this).css(prop)) continue;
            if ($(this).data(prop) != $(this).css(prop)) continue;

            if (($(this).css(prop) === 'rgba(0, 0, 0, 0)') || ($(this).css(prop) === 'transparent')) {
                if ($(this).is('body')) {
                    $(this).css(prop, 'black');
                    continue;
                } else {
                    continue;
                }
            }
            color = new RGBColor($(this).css(prop));
            if (color.ok) {
                $(this).css(prop, 'rgb(' + (255 - color.r) + ',' + (255 - color.g) + ',' + (255 - color.b) + ')');
            }
            color = null;
        }
    }

    function setColorData() {
        var colorProperties = ['color', 'background-color'];
        for (var prop in colorProperties) {
            prop = colorProperties[prop];
            $(this).data(prop, $(this).css(prop));
        }
    }

    function invertColors() {
        $(document).live('DOMNodeInserted', function(e) {
            var $toInvert = $(e.target).find('*').andSelf();
            $toInvert.each(setColorData);
            $toInvert.each(invertElement);
        });
        $('*').each(setColorData);
        $('*').each(invertElement);
        $('iframe').each(function () {
            $(this).contents().find('*').each(setColorData);
            $(this).contents().find('*').each(invertElement);
        });
    }
    load_script('http://www.phpied.com/files/rgbcolor/rgbcolor.js', function () {
        if (!window.jQuery) load_script('https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', invertColors);
        else invertColors();
    });

})(jQuery);

Now works with most sites I've tried. Background images can pose a problem, however.

Answer

Jacob Relkin picture Jacob Relkin · Jan 22, 2011

First things first, grab the awesome RGBColor class here.

Here goes:

jsFiddle example

//set up color properties to iterate through
var colorProperties = ['color', 'background-color'];

//iterate through every element in reverse order...
$("*").get().reverse().each(function() {
    var color = null;

    for (var prop in colorProperties) {
        prop = colorProperties[prop];

        //if we can't find this property or it's null, continue
        if (!$(this).css(prop)) continue; 

        //create RGBColor object
        color = new RGBColor($(this).css(prop));

        if (color.ok) { 
            //good to go, let's build up this RGB baby!
            //subtract each color component from 255
            $(this).css(prop, 'rgb(' + (255 - color.r) + ', ' + (255 - color.g) + ', ' + (255 - color.b) + ')');
        }
        color = null; //some cleanup
    }
});

Screenshot:

alt text

EDIT: Here's a bookmarklet you can now copy-paste into your browser (http://jsfiddle.net/F7HqS/1/)

javascript:function load_script(src,callback){var s=document.createElement('script');s.src=src;s.onload=callback;document.getElementsByTagName('head')[0].appendChild(s);}function invertColors(){var colorProperties=['color','background-color'];$('*').each(function(){var color=null;for(var prop in colorProperties){prop=colorProperties[prop];if(!$(this).css(prop))continue;color=new RGBColor($(this).css(prop));if(color.ok){$(this).css(prop,'rgb('+(255-color.r)+','+(255-color.g)+','+(255-color.b)+')');}color=null;}});}load_script('http://www.phpied.com/files/rgbcolor/rgbcolor.js',function(){if(!window.jQuery)load_script('https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js',invertColors);else invertColors();});