ITCSS y Atomic CSS: ordenar y atomizar
El triángulo invertido de Harry Roberts como implementación manual de @layer, y la propuesta de 2013 que anticipó el CSS de utilidades quince años antes de que ganara.
ITCSS y Atomic CSS son las dos metodologías clásicas que más se parecen a lo que hacemos hoy, y ninguna de las dos por casualidad. ITCSS describe un orden de capas idéntico al que escribes con @layer, ocho años antes de que @layer existiera. Atomic CSS propuso en 2013 exactamente el modelo que popularizó Tailwind, fue recibido con hostilidad casi unánime, y hoy es mayoritario. Vale la pena leer ambas con atención, porque son el puente directo entre la historia y lo que discutiremos en el nivel siguiente.
- Describir las siete capas de ITCSS y el criterio que las ordena.
- Traducir una arquitectura ITCSS a
@layery ver qué se gana. - Explicar la propuesta de Atomic CSS y el argumento con el que se defendía.
- Identificar qué objeciones de 2013 siguen en pie y cuáles resolvió el tiempo.
ITCSS: el triángulo invertido
ITCSS —Inverted Triangle CSS, Harry Roberts, alrededor de 2014— no es una convención de nombres. Es una regla de orden: organiza el CSS en capas y colócalas de forma que, al bajar por el fichero, tres magnitudes crezcan siempre de forma monótona.
- El alcance disminuye: de reglas que afectan a todo a reglas que afectan a un elemento.
- La especificidad aumenta.
- La explicitud aumenta: de reglas genéricas a reglas dirigidas a algo concreto.
Con esas tres magnitudes creciendo en el mismo sentido, se elimina el conflicto: una regla nunca necesita vencer a otra que viene después, porque las que vienen después son siempre más específicas y más dirigidas. Las capas canónicas son siete:
| Capa | Qué contiene |
|---|---|
| Settings | variables, sin producir CSS |
| Tools | mixins y funciones, sin producir CSS |
| Generic | reset, box-sizing, normalización |
| Elements | estilos de elementos HTML sin clases |
| Objects | patrones estructurales sin decoración |
| Components | los componentes de la interfaz |
| Utilities | ayudantes de un solo propósito, con !important |
El nombre viene de dibujarlas como un triángulo apuntando hacia abajo: arriba, capas que alcanzan a mucho; abajo, capas que alcanzan a poco. Y la última capa lleva !important por diseño, no por rendición: una utilidad se escribe precisamente para ganar siempre, y en un sistema sin capas en cascada !important era la única forma de expresarlo.
Ese detalle es la mejor prueba de que ITCSS era una implementación manual de algo que faltaba en el lenguaje. Todo lo que hace se escribe hoy en una línea:
@layer generic, elements, objects, components, utilities;
Y con eso desaparecen tres cosas de golpe. Desaparece el !important de las utilidades, porque la última capa ya gana. Desaparece la dependencia del orden de los ficheros, porque el orden lo fija la declaración y no el empaquetador. Y desaparece la fragilidad ante la carga diferida: una capa declarada antes sigue perdiendo aunque su CSS llegue después por red, que era el bug irreproducible de las aplicaciones con división de código.
Las dos primeras capas de ITCSS, Settings y Tools, tampoco existen ya como tales. Settings eran variables de Sass; hoy son custom properties que viven en la cascada y se pueden sobrescribir en un subárbol o cambiar en runtime. Tools eran mixins; una buena parte de lo que hacían lo hacen ahora clamp(), min(), max(), color-mix() y los colores relativos, que además calculan en el navegador y no en el build.
Al pasar ITCSS a @layer hay una decisión que la versión clásica no podía tomar: qué dejar fuera de todas las capas. Cualquier regla sin capa gana a todas las capas, siempre. Eso convierte “sin capa” en la capa más fuerte de todas, y es el sitio correcto para las anulaciones de emergencia y para el CSS de terceros que no controlas. En ITCSS no había forma de expresar eso salvo !important.
Atomic CSS: la propuesta que se adelantó quince años
En 2013, Thierry Koblentz publicó desde Yahoo un artículo con el título deliberadamente provocador de “Challenging CSS Best Practices”. La propuesta: dejar de escribir clases semánticas que describen qué es un elemento, y escribir clases que describen qué hace una declaración. Una clase, una declaración.
<div class="D-f Ai-c P-10 Bgc-blanco Bdrs-8">…</div>
La reacción de la comunidad fue de rechazo casi unánime, y los argumentos en contra eran serios: eso es escribir estilos en línea con pasos extra, rompe la separación entre presentación y contenido, hace el HTML ilegible, y si cambias un valor tienes que tocar todas las plantillas.
Los argumentos a favor eran menos intuitivos pero más difíciles de rebatir. El primero es de tamaño: en una hoja semántica, el CSS crece con el número de componentes, porque cada componente nuevo trae reglas nuevas. En una hoja atómica crece con el número de valores distintos usados en el proyecto, que se satura muy pronto. A partir de cierto tamaño de aplicación, la hoja atómica es más pequeña, y sigue siéndolo por mucho que el proyecto crezca.
El segundo es de borrado: una clase de utilidad no tiene dueño, así que borrar un componente del HTML no deja CSS huérfano. El problema del código muerto, que ninguna metodología semántica había resuelto, simplemente no existe en este modelo.
El tercero es de conflictos: las utilidades no colisionan porque cada una hace una sola cosa y ninguna alcanza a nada que no lleve su clase. La especificidad es plana por construcción, sin disciplina.
Y el cuarto, el menos evidente, es de restricción: si las clases disponibles salen de una escala definida, es literalmente imposible escribir un valor fuera del sistema. No hay que revisar que nadie use padding: 13px; no existe la clase.
La objeción que sí quedó en pie, y que sigue en pie, es la repetición. Si veinte tarjetas comparten las mismas doce clases, ese conjunto de doce clases está repetido veinte veces en el HTML, y no hay ningún sitio donde esté escrito que “así es una tarjeta”. La respuesta que se dio entonces —y que sigue siendo la respuesta— es que ese sitio es el componente de la plantilla, no el CSS. Es una respuesta legítima y tiene consecuencias reales, y es exactamente el eje del debate que se retoma en el nivel siguiente.
Por qué la propuesta de 2013 fracasó y la de 2019 triunfó
La idea era la misma. Lo que cambió fue el contexto, y son tres cosas concretas.
La generación desde el marcado. En 2013, la biblioteca de utilidades se escribía a mano o se generaba entera, y en cualquier caso se enviaba entera. Enviar decenas de miles de clases de las que usas doscientas era inaceptable. Cuando aparecieron los motores que escanean el marcado y generan solo las clases que aparecen en él, el coste de la biblioteca dejó de existir.
Los componentes. En 2013 el HTML se escribía a mano o con plantillas de servidor, y la repetición de doce clases en veinte sitios era literal. Con componentes, la repetición está en un archivo y se instancia veinte veces. La objeción principal se debilitó muchísimo, no porque el argumento fuera falso sino porque el entorno cambió.
El agotamiento con lo semántico. Diez años de guerras de especificidad, de hojas que nadie se atrevía a borrar y de discusiones sobre si una clase debía llamarse .card o .panel produjeron una comunidad dispuesta a considerar la alternativa. Los argumentos de Koblentz no mejoraron; mejoró la disposición a escucharlos.
Hay un fenómeno que conviene tener presente porque te va a pasar otra vez, y no solo con CSS. La propuesta de Atomic CSS de 2013 y el modelo de utilidades que hoy usa una parte enorme de la industria son la misma idea técnica, con los mismos argumentos a favor y las mismas objeciones en contra. La primera fue rechazada con dureza y la segunda ganó. Entre medias no apareció ningún argumento nuevo: apareció un compilador que eliminó el coste de tamaño y un modelo de componentes que eliminó el coste de repetición. Es decir, lo que hizo viable la idea fue que cambió el precio, no la razón. La lección práctica es doble y las dos mitades son incómodas. Primero: cuando descartes una técnica, anota si la descartas por el argumento o por su coste actual, porque los costes bajan y los argumentos no, y una idea archivada por precio hay que reabrirla cuando el precio cambia. Segundo, y más importante para tu criterio: gran parte de lo que la comunidad presenta como principios de arquitectura son en realidad optimizaciones para restricciones concretas de un momento. La separación estricta entre presentación y contenido tenía un valor altísimo cuando el mismo HTML se reestilaba entero desde fuera, como en CSS Zen Garden. Con componentes que encapsulan marcado y estilo juntos, ese valor se desploma, porque ya no hay nadie que quiera reestilar tu HTML sin tocarlo. Ninguna de las dos posturas es una verdad eterna; las dos son respuestas correctas a mundos distintos, y la habilidad que hay que desarrollar es reconocer en cuál de los dos estás.