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.