Created December 2024
:root Color Properties Editor (Bookmarklet)
Many websites have colors defined at their :root
. This
bookmarklet allows you to edit those colors by adding a widget to the page. Note that to be included
they must include the word "color" in them or have a color hex or rgb value.
⚠️ Warnings
-
Just because the custom properties are at the
:root
doesn't mean there will be a visible effect. - Chrome does not correctly expose CSS Custom Properties via getComputedStyle. See 41451306: getComputedStyles does not include CSS Custom Properties
Drag the link below to your browser's toolbar...
Source Code
var ROOT_COLOR_PROPERTIES_EDITOR = {
id: 'color-properties-editor-element',
new_element_prefix: 'color-properties-editor-',
// I suppose in theory you could point this at different elements and reinitialize
source_element: document.documentElement,
init: function () {
if (!document.getElementById(ROOT_COLOR_PROPERTIES_EDITOR.id)) {
ROOT_COLOR_PROPERTIES_EDITOR.createColorsElement();
}
let rootStyles = getComputedStyle(ROOT_COLOR_PROPERTIES_EDITOR.source_element);
let count_found = 0;
for (var i = 0; i < rootStyles.length; i++) {
var key = rootStyles[i];
var property_has_color_name = key.toLowerCase().indexOf('color') !== -1;
var value_starts_with_rgb = rootStyles.getPropertyValue(key).indexOf('rgb') === 0;
var value_starts_with_hsl = rootStyles.getPropertyValue(key).indexOf('hsl') === 0;
var value_valid_hex_3 = rootStyles.getPropertyValue(key).match(/^#[0-9a-f]{3}$/i);
var value_valid_hex_4 = rootStyles.getPropertyValue(key).match(/^#[0-9a-f]{4}$/i);
var value_valid_hex_6 = rootStyles.getPropertyValue(key).match(/^#[0-9a-f]{6}$/i);
var popular_keyword_colors = ['red', 'green', 'blue', 'yellow', 'orange', 'purple', 'pink', 'brown', 'black', 'white', 'gray', 'grey', 'transparent'];
var value_is_color_keyword = popular_keyword_colors.indexOf(rootStyles.getPropertyValue(key).toLowerCase()) !== -1;
let color_criteria = property_has_color_name || value_starts_with_rgb || value_valid_hex_3 || value_valid_hex_4 || value_valid_hex_6 || value_is_color_keyword || value_starts_with_hsl;
if (key.indexOf('--') === 0 && color_criteria) {
var label = document.createElement('label');
label.textContent = key;
label.htmlFor = ROOT_COLOR_PROPERTIES_EDITOR.new_element_prefix + key;
label.title = `Original value: ${rootStyles.getPropertyValue(key)}`;
label.style.whiteSpace = 'nowrap';
label.style.fontSize = '0.8rem';
var input = document.createElement('input');
input.type = 'color';
input.id = ROOT_COLOR_PROPERTIES_EDITOR.new_element_prefix + key;
input.value = rootStyles.getPropertyValue(key);
input.addEventListener('input', function (event) {
ROOT_COLOR_PROPERTIES_EDITOR.source_element.style.setProperty(event.target.id.replace(ROOT_COLOR_PROPERTIES_EDITOR.new_element_prefix, ''), event.target.value);
});
document.getElementById(ROOT_COLOR_PROPERTIES_EDITOR.id).appendChild(label);
document.getElementById(ROOT_COLOR_PROPERTIES_EDITOR.id).appendChild(input);
count_found++;
}
}
if (count_found === 0) {
var message = 'No colors found in root element. ';
if (navigator.userAgent.indexOf('Chrome') !== -1) {
var href = 'https://issues.chromium.org/issues/41451306?pli=1';
var text = 'Chromium Bug 41451306: getComputedStyles does not include CSS Custom Properties';
var a = document.createElement('a');
a.href = href;
a.textContent = text;
a.style.color = '#fff';
a.target = '_blank';
message += 'See: ';
message += a.outerHTML;
}
var noColors = document.createElement('p');
noColors.innerHTML = message;
noColors.style.gridColumn = 'span 2';
noColors.style.whiteSpace = 'nowrap';
document.getElementById(ROOT_COLOR_PROPERTIES_EDITOR.id).appendChild(noColors);
}
}, createColorsElement: function () {
var colorsElement = document.createElement('div');
colorsElement.id = this.id;
colorsElement.style.fontFamily = 'verdana, sans-serif';
colorsElement.style.width = 'min-content';
colorsElement.style.height = 'auto';
colorsElement.style.maxHeight = '100vh';
colorsElement.style.position = 'fixed';
colorsElement.style.bottom = '0';
colorsElement.style.left = '0';
colorsElement.style.padding = '1rem';
colorsElement.style.display = 'grid';
colorsElement.style.gridTemplateColumns = 'min-content min-content';
colorsElement.style.gap = '1px 1ch';
colorsElement.style.flexWrap = 'wrap';
colorsElement.style.color = 'white';
colorsElement.style.backgroundColor = 'rgba(0,0,0,0.5)';
colorsElement.style.borderRadius = '1rem';
colorsElement.style.boxSizing = 'border-box';
// CNN has so many, I had to add this
colorsElement.style.zIndex = '10000'; //
colorsElement.style.overflow = 'auto';
document.body.appendChild(colorsElement);
}
};
ROOT_COLOR_PROPERTIES_EDITOR.init();
What can be done about Chrome?
// Until Chromium supports getting custom properties via getComputedStyle
// https://issues.chromium.org/issues/41451306?pli=1
// Maybe we can do a workaround by fetching and then inspecting
// everything referred to in a link tag or style tag, then parsing all the CSS?
// This is a terrible idea.
var links = document.getElementsByTagName('link');
for (var i = 0; i < links.length; i++) {
var rel_is_stylesheet = links[i].rel === 'stylesheet';
var type_is_css = links[i].type === 'text/css';
var href_exists = links[i].href;
var href_contains_css = href_exists && links[i].href.indexOf('css') !== -1;
if (rel_is_stylesheet || type_is_css || href_contains_css) {
fetch(links[i].href).then(function (response) {
return response.text();
}).then(function (text) {
console.log(text);
// TODO find all the custom properties in the CSS and expose
});
}
}
var style_tags = document.getElementsByTagName('style');
for (var i = 0; i < style_tags.length; i++) {
console.log(style_tags[i].textContent);
// TODO find all the custom properties in the CSS and expose
}