Paleta de color CSS-3

Aplicación de la paleta de color

Como ejemplo de aplicación tenemos un desplegable que nos permite aplicar el color sobre el fondo del elemento {background-color}, el color de primer plano {color} o el color del borde {border-color} a cualquier elemento de este documento:

Ejemplo:

Color del elemento a editar
Cargando módulos: cargando

Aquí tenemos una tabla con unas celdas y varios colores para hacer pruebas usando click sobre cualquiera de estos elementos o de cualquier otro de esta página:

color: yellow; background-color: rgb(255,0,0); border: olive solid 5px;

color: rgb(25,25,51); background-color: rgb(100%,64.71%,9%); border: #0000FF solid 5px;

color: lightgray; background-color: chocolate; border: transparent solid 5px;

Este <div> esta "montado" encima de otro con una imagen en mosáico para observar la opacidad. En este caso usamos rgba(red, green, blue, opacity) tal como se especifica en CSS-3 rgba color:

Transparencia

Por último una tabla con los 17 colores básicos de CSS que aparecen en color keywords CSS2 para probar los nombres de color:

blacknegrorgb(0,0,0)
graygrisrgb(128,128,128)
silverplatargb(192,192,192)
whiteblancorgb(255,255,255)
navymarinorgb(0,0,128)
blueazulrgb(0,0,255)
aqua (cyan)agua (cyan)rgb(0,255,255)
greenverdergb(0,128,0)
tealtealrgb(0,128,128)
oliveolivargb(128,128,0)
limelimargb(0,255,0)
yellowamarillorgb(255,255,0)
maroonmarrónrgb(128,0,0)
purplepúrpurargb(128,0,128)
redrojorgb(255,0,0)
orangenaranjargb(255,165,0)
fuchsia (magenta)fucsia (magenta)rgb(255,0,255)

Esta aplicación no debería tener problemas con Firefox 6.0, Safari 5.0, Chrome 14.0 y Opera 11.51. Explorer 8-9 no admite HSL ni colores rgba(), por lo que esta aplicación no funcionará con este navegador en esos detalles. Por ejemplo, el color de fondo {background-color} tiene un valor inicial transparent que se aplicará cuando no se especifique ninguno. Por lo tanto si hacemos alt+dblclick sobre el fondo de este texto, un elemento <p> sin color de fondo, en Explorer 8-9 nos saldrá el color de fondo blanco con el valor rgb(255,255,255) white (ERROR). Esto significa que no se pudo actualizar un color y en su defecto se presenta el color blanco agregando esa palabra "error". El valor correcto para un color transparente debería ser rgba(0,0,0,0.0), tal como lo define CSS-3 transparent color. Para verificar de forma visual la transparencia se dispone de un elemento con la letra "T" y borde en una capa inferior a la del color.

Cuando se abre la paleta con un color se actualizará la pestaña de edición con los valores de color rojo, verde, azul y opacidad. Se selecciona el color en la lista de nombres de color si existe. En cuanto a los cubos de color, se buscará el color más próximo, pues es obvio que el cubo RGB o HSL no contiene todos los colores posibles.

Ventana de propiedades CSS con un formulario emergente

Usando el cubo de color y otras utilidades podemos construir una paleta de colores para modificar las propiedades de estilo de color de un documento. Para ello necesitamos una ventana o formulario emergente. Pero con la finalidad de reutilizar los objetos, aplicaremos los conceptos de herencia en Javascript.

En primer lugar creamos un objeto que denominaremos paletaColor conteniendo unos elementos que nos permitirán seleccionar el color desde una rejilla de colores. Además tendrá otras funcionalidades como edición de color, una lista desplegable con todos los colores con nombre CSS según la especificación oficial nombres color SVG y por último le agregamos el cubo de color del tema anterior. En definitiva, tenemos los siguientes objetos identificados:

  1. El cubo de color del tema anterior
  2. Un formulario emergente
  3. Una paleta de color, objeto que contiene a su vez el objeto cubo de color.

Podemos pensar que una paleta de color tiene un cubo de color: se trata de una composición de objetos. Además una paleta de color es un formulario emergente. Por lo tanto aplicaremos el concepto de herencia, es decir, la paleta de color hereda del formulario emergente. De esta forma el módulo paleta-color.js nos servirá para declarar la clase paletaColor que maneja ese objeto y también contiene la siguiente función que aplica herencia con el mecanismo del encadenamiento de prototipo (prototype chaining):

function crearPaletaColor(nombreForm, cadenaTitulo, conPantalla, conBotones, moverForm){
    paletaColor.prototype = new formEmerge(nombreForm, cadenaTitulo, conPantalla, 
            conBotones, moverForm);
    var temporal = new paletaColor();
    forms.push(temporal);
    return temporal;
}

Esta función nos permitirá crear una instancia de la clase paletaColor heredando de la clase formEmerge, el formulario emergente. Así en el script de este documento declaramos en la carga:

var paleta = null;

window.onload = function(){
    paleta = crearPaletaColor("paleta", "", false, 3, "marco");
    paleta.eventoAceptar = true;
    paleta.ejecutaEventoAceptar = aceptarColor;
    var ejemplo = document.getElementById("ejemplo1");
    ejemplo.addEventListener("click", abrirPaleta, false);
}

Tras crear un nueva instancia paleta, activamos el evento aceptar que se ejecutará con un evento onclick sobre cualquier elemento del ejemplo. Por un lado tenemos la función abrirPaleta(evento) que recogerá el evento abriéndose el formulario emergente:

function abrirPaleta(event){
    var obj = wxG.recogeEvento(event);
    if (!obj.element.hasAttribute("data-mpaleta") &&
       (!(obj.element.id && (obj.element.id.indexOf("IDCUBO")>-1)))){
        elemento = obj.element;
        var queColor = wxG.descambiaGuiones(document.getElementById("que-color").value);
        var color = wxGC.colorRgb(wxG.estiloActual(elemento, queColor));
        paleta.actualiza(color);
        var izquierda = obj.pagx;
        var arriba = obj.pagy;
        var titulo = "Elemento <" + elemento.tagName.toLowerCase() + ">";
        var id = elemento.getAttribute("id");
        if (id) titulo += ' id="' + id + '"';
        paleta.abrir("",titulo,izquierda,arriba);
        if (obj.event.preventDefault) {
            obj.event.preventDefault();
        } else { //IE
            obj.event.returnValue = false;
        }                
    }            
}

La función recogeEvento() nos permite gestionar el evento y obtener el elemento que lo causó así como su posición en la página. Antes de abrir la paleta actualizamos su color para que lo muestre en sus cuatro apartados: rejilla, edición, lista SVG y cubo de color. Por último abrimos la paleta con paleta.abrir() llamando al método heredado que abre el formulario emergente. Cuando pulsemos el botón aceptar en el formulario emergente se ejecutará el evento aceptar que da lugar al cambio de color del elemento con esta función:

function aceptarColor(){
    var queColor = document.getElementById("que-color").value;
    elemento.style[queColor] = paleta.respuesta;
}

Recursos de la paleta de color

Esta paleta de color usa los siguientes recursos declarados en la cabecera de este documento:

  • Para el objeto formulario emergente necesitamos la hoja de estilo form-emerge.css y el script form-emerge.js
  • Para el objeto cubo de color necesitamos cubo-color.css y cubo-color.js
  • Para la propia paleta de color necesitamos paleta-color.css y paleta-color.js
  • También son necesarios los módulos generales de Javascript general.js y general.color.js. En este último recopilamos diversas funciones de uso genérico para gestionar el color.
  • Para manejar las listas de colores con nombre necesitamos el módulo carga-xml-css.js

El código de todo esto puede consultarse fácilmente con las opciones de ver código del navegador Firefox. Hay más detalles en javascript general.js para ese módulo. En cuanto al módulo carga-xml-css.js se trata de un simple cargador para acceder al XML que expone todas las propiedades de CSS con AJAX:

var versionCss = "css21";
var listaCss = null;
var listaColoresCss = null;
var listaColoresCss_titulo = "";
var listaColoresSvg = null;
var listaColoresSvg_titulo = "";
try {
    var request = null;
    if (window.XMLHttpRequest){
        request = new XMLHttpRequest();
    } else {
        request = new ActiveXObject("Microsoft.XMLHTTP"); 
    }
    if (request){
        request.open("GET", "/res/xml/" + versionCss + ".xml", false);
        request.onreadystatechange = function(){
            if ((request.readyState == 4)&&(request.status == 200)){
                listaCss = request.responseXML;
                if (listaCss){
                    var nodos = listaCss.getElementsByTagName("valuesdef");
                    for (var i=0; i<nodos.length; i++){
                        var attr = nodos[i].getAttribute("id")
                        if (attr == "colors"){
                            listaColoresCss = nodos[i].getElementsByTagName("value")
                            listaColoresCss_titulo = nodos[i].getAttribute("title");
                        } else if (attr == "colors-svg"){
                            listaColoresSvg = nodos[i].getElementsByTagName("value")
                            listaColoresSvg_titulo = nodos[i].getAttribute("title");
                        }                    
                    }
                }
            }
        }
        request.setRequestHeader("Cache-Control", "no-cache, must-revalidate");
        request.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2005 00:00:00 GMT");                
        request.send();
    } else {
        alert("No hay objeto XMLHttpRequest.");
    }
} catch (e) {
    alert("No se pudo crear un objeto XML. " + e.message);
}

Como expuse en el primer tema sobre propiedades CSS en un XML, el archivo css21.xml es una recopilación de todas las propiedades de CSS-2.1 aunque también contiene la lista de colores SVG. Este conjunto de propiedades lo confeccioné hace un par de años. El cubo no usa este XML en ningún caso. Pero la paleta de color necesita las listas de colores básicos y SVG. Por lo tanto este recurso tiene más cosas que las que necesitamos para la paleta de color. Pero mi propósito es seguir actualizando esta recopilación para adaptarla a CSS-3 y ofrecer el resto de posibilidades de edición CSS.

El módulo carga-xml.js se ocupa de la carga de ese XML usando un gestor simple con peticiones AJAX. Esto nos sirve para rellenar las variables globales listaColoresCss para los colores con nombres básicos de CSS y la listaColoresSvg para la extendida. La variable listaCss contiene todo el XML. Será a partir de esta variable donde podremos acceder a cualquiera de las propiedades CSS.