La petición llega siempre con la misma forma. Una sección de campaña con la identidad de una marca asociada, en mitad de una página que ya tiene su tema. O un bloque editorial en tonos cálidos dentro de un producto que es gris y azul. La pieza es visualmente distinta del resto de la página, pero por dentro son los mismos botones, los mismos campos y las mismas tarjetas.
La respuesta habitual del sistema de diseño es una hoja de estilos paralela.
Aparecen clases tipo --on-dark, una variante de botón para fondos oscuros, otra
de campo de formulario, y una regla de contexto por cada componente que pueda
caer dentro del bloque. En la práctica eso significa mantener dos versiones de
cada componente, revisar dos veces cada cambio y descubrir en el tercer trimestre
que la variante de campaña se quedó sin el estado de foco que sí se arregló en la
principal.
El planteamiento alternativo es cambiar dónde vive el tema. Si el tema no es una propiedad de la página sino de un contenedor, el bloque de campaña no necesita componentes distintos: necesita declarar que dentro de él rige otro contrato de color. A ese contenedor lo llamo isla de temas.
Una isla es un subárbol con su propio contrato de color
La definición es corta: un elemento marca en el DOM qué tema rige a partir de ahí, y todo lo que cuelga de él adopta ese tema sin saber que está dentro de una isla. Un botón dentro de la isla de campaña se pinta con los colores de la campaña y su código fuente no cambia ni una línea. Tampoco cambia el de la tarjeta que lo contiene, ni el del campo de formulario que tiene al lado.
Lo que hace útil el modelo es que no introduce un mecanismo nuevo. El tema
global de esta web es exactamente el mismo mecanismo aplicado al elemento
<html>, que en este repositorio lleva el nombre de isla page. La página es la
isla número cero. Cuando la sección «Café Ácido» de mi página de perfil declara
su tema editorial, no está usando una excepción del sistema: está haciendo lo
mismo que hace la raíz, un nivel más abajo. Las islas se pueden anidar y cada una
solo redefine lo que declara; el resto lo hereda de la de arriba.
Esa uniformidad tiene una consecuencia práctica que se nota al depurar. No hay una ruta de código para «el tema de la página» y otra para «el tema de este bloque», así que tampoco hay dos sitios donde puedan divergir.
Lo que deja de costar
Lo que justifica el patrón ante quien paga las horas es la partida de mantenimiento que desaparece.
Empieza por las variantes de contexto. Un sistema con cuarenta componentes que resuelve los fondos oscuros duplicando variantes tiene ochenta piezas que mantener, y cada corrección hay que aplicarla dos veces o justificar por qué no. Con islas, la cifra vuelve a cuarenta. Ese ahorro no se nota el día que se implementa el patrón; se nota en cada corrección de los dos años siguientes, repartido en trozos demasiado pequeños para aparecer en ningún informe.
Sigue por quién ejecuta el encargo. Añadir un tema de isla consiste en escribir un bloque de dieciséis declaraciones de color y una línea en el registro de temas. No se abre ningún archivo de componente, de modo que el cambio no puede romper nada fuera de las páginas que lo usen. Eso mueve la tarea de sitio: deja de ser una modificación del sistema de diseño, con su revisión y su cola, para convertirse en configuración.
El contraste, que es la parte que suele degradarse en las campañas, se decide una sola vez. En cada tema de isla, el fondo y el texto de una superficie se declaran juntos, en el mismo bloque y a la vista. La verificación se hace sobre esos pares cuando se crea el tema, no sobre cada pantalla donde el bloque vaya a aparecer. Sigue siendo trabajo obligatorio, pero es una tarea acotada de diez minutos en lugar de una auditoría por campaña.
Y la marca blanca resulta ser el mismo mecanismo. Un producto que se vende con la identidad visual del cliente, o un widget embebido en el sitio de un tercero, plantean el mismo problema que la campaña: un subárbol con otro contrato de color. Si el patrón ya está montado para la sección promocional, la capacidad multimarca deja de ser un proyecto y pasa a ser un archivo de tokens más.
Un tema nuevo, en una tarde
De todo el montaje, lo que más ha cambiado mi forma de trabajar es el bucle de prueba. Esta web lleva un panel de temas que recorre el DOM buscando islas y monta un selector por cada una. Desde ahí se le puede cambiar el tema a cualquier bloque de la página en vivo, incluida la raíz, y ver de inmediato cómo queda el contenido real con sus textos y sus imágenes.
Debajo de la lista hay dos cosas más. Un objeto JSON con el tema que tiene cada isla en ese momento, que es la configuración de la vista lista para copiar, y un constructor de temas con un selector de color por cada uno de los dieciséis tokens. Al terminar, el panel devuelve el bloque CSS del tema para pegarlo en el archivo de temas de isla.
Con esa herramienta, probar una identidad de campaña sobre contenido real deja de necesitar una rama, un despliegue de previsualización y una reunión. Se hace en la propia página, se copia el bloque resultante y el trabajo de ingeniería es pegarlo. Lo que antes se discutía sobre una maqueta estática se decide sobre la página que va a salir.
Por debajo hay un componente pequeño y una cadena de tokens
El componente que activa una isla ocupa poco más de cincuenta líneas y su trabajo en tiempo de ejecución es ninguno. Recibe el tema, resuelve dos atributos de datos y los escribe en el elemento que envuelve al contenido:
<ThemeIsland theme="editorial" name="cafe-acido" as="section">
<!-- cualquier contenido: se tiñe solo -->
</ThemeIsland>
De ahí sale un <section> con data-theme="light" y
data-island-theme="editorial". No hay JavaScript en cliente, no hay contexto de
framework y no hay estado que sincronizar: el componente entero se reduce a esos
dos atributos escritos en el HTML durante el renderizado.
Lo que hace el trabajo de verdad está debajo, y es la arquitectura de tokens en cuatro capas que ya describí en «Cuándo un sistema de tokens necesita cuatro capas». Un tema de isla no toca la capa de primitivos ni la semántica: reasigna únicamente tokens de rol, que son los que están hechos para conmutar. Como los componentes consumen roles y nunca valores, la reasignación llega hasta el último elemento anidado sin que ninguno se entere.
El modelo concreto es esquema base más superficies. El tema de isla declara si
parte de claro u oscuro, y con esa sola declaración hereda el color-scheme, la
familia de acciones, el anillo de foco y el resto del sistema, todo ya
verificado. Encima de esa base, una regla sobrescribe únicamente las superficies:
fondo, texto, icono y borde de las variantes base, sutil y de acento, más el
diálogo modal. Son dieciséis tokens, y ahí termina toda la superficie de
personalización de un tema.
El detalle de cómo se resuelve la cascada, por qué la regla de adopción usa
inherit como valor de reserva y cómo se evita el parpadeo al cargar con el tema
guardado da para su propio artículo, y lo escribiré aparte.
Lo que cuesta y dónde deja de valer
La decisión que más condiciona el resultado es esa de limitar el tema de isla a las superficies. La alternativa era dejar que cada tema declarase el juego completo de tokens de rol, acciones y foco incluidos, con lo que un botón dentro de la isla de campaña podría llevar el color del partner. La descarté porque convierte cada tema nuevo en una revisión completa de accesibilidad: estados hover y activo, contraste del texto sobre cada variante de botón y visibilidad del anillo de foco sobre el fondo nuevo. Multiplicado por cada campaña, eso no lo sostiene ningún equipo.
El precio de haberla descartado es concreto y conviene decirlo antes de que lo descubra quien monte la primera campaña: dentro de una isla, los botones salen con los colores del esquema base, no con los del tema. Está a la vista en la primera captura: el botón de acento es lima en las dos islas y el primario solo cambia porque cambia el esquema, claro sobre el marrón y negro sobre el crema. Ninguno de los dos toma el dorado del tema. Cuando una campaña necesite de verdad su propio color de acción, quedan dos salidas y las dos son trabajo consciente: usar la capa de componente en esa vista concreta, o ampliar el registro de tokens de isla y asumir entonces sí la verificación de estados.
El límite de validez es el de siempre en este tipo de arquitectura. Un producto con un solo tema, sin campañas y sin clientes que quieran su marca encima no necesita nada de esto; le sobra con tokens semánticos bien nombrados y una regla que prohíba los hexadecimales en los componentes. Las islas empiezan a pagarse cuando aparece el segundo bloque con identidad propia, y se vuelven la opción barata cuando ese bloque tiene que convivir con los dos temas del sistema.
El criterio que aplico para decidirlo cabe en una comprobación: si al mirar el diseño hay que preguntarse «¿y este botón, de qué color va aquí?», el tema ya no es una propiedad de la página.