Arquitectura CSS y estrategias de naming | Nicolás GarzónTexto
baja especificidad
+ límites claros
+ estados explícitos
+ orden de cascada conocido
= cambios predecibles
Texto
tokens
reset
base
layout
components
utilities
exceptions
No es obligatorio usar estas categorías exactas. Cada una debe tener una función y una prioridad definida.
CSS
@layer base {
body {
margin: 0;
color: var(--color-text-default);
background: var(--color-surface);
}
}
Estiliza elementos y defaults amplios, no detalles internos de componentes.
CSS
.stack {
display: grid;
gap: var(--stack-space, 1rem);
}
.cluster {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--cluster-space, 0.75rem);
}
Representan relaciones reutilizables sin conocer el dominio.
CSS
.card {
display: grid;
gap: 1rem;
}
.card__title { ... }
.card[data-variant="featured"] { ... }
Un componente define estructura visual, variantes y estados propios.
CSS
.sr-only { ... }
.text-center { text-align: center; }
Son pequeñas, explícitas y con una política de prioridad conocida.
No deberían convertirse en nombres ambiguos que ocultan varias decisiones.
CSS
.card { }
.card__title { }
.card--featured { }
Aporta nombres globalmente claros:
- Block.
- Element.
- Modifier.
No requiere anidar cada selector ni reflejar cada nodo del DOM.
Organiza Composition, Utility, Block y Exception. Prioriza que layout global y bloques locales tengan responsabilidades separadas.
Ordena estilos desde genéricos y de baja especificidad hacia componentes/utilities más explícitos.
Introdujeron separación entre estructura/skin y categorías de reglas. Son ideas útiles, no leyes que deban combinarse todas.
El build transforma nombres para scope local. Reduce colisiones, pero no elimina cascada, herencia, global styles ni necesidad de arquitectura.
Puede ofrecer co-location, props dinámicas y eliminación por bundle. También puede añadir runtime, orden de inyección y dependencia del framework.
- Runtime CSS-in-JS.
- Extraction estática.
- Inline style objects.
- Generated atomic CSS.
Aísla selectores y parte de styling mediante host, parts y custom properties.
No elimina herencia, tokens ni necesidad de estados accesibles.
CSS
.red-box-left { ... }
CSS
.alert[data-severity="error"] { ... }
El nombre comunica propósito y el atributo representa la variante.
CSS
.button[aria-expanded="true"] { ... }
.input[aria-invalid="true"] { ... }
Utiliza estados semánticos reales cuando existen. Para estado interno de aplicación, una clase o data-* puede ser correcta.
CSS
.dashboard .sidebar .card h3 { ... }
Acopla el componente a una página. Mejor crea una variante, token local o layout contract.
Una excepción debe explicar:
- Qué contrato rompe.
- Por qué.
- Dónde puede aplicarse.
- Si debe convertirse en variante reusable.
- Elegir una metodología sin entender el problema.
- Reflejar todo el DOM en nombres BEM.
- Confiar en CSS Modules como arquitectura completa.
- Crear selectores por página que modifican componentes.
- Mezclar layout externo e interno.
- Usar nombres visuales que envejecen.
- Crear utilities con muchas responsabilidades.
- Arquitectura CSS controla dependencias y overrides.
- Base, layout, components y utilities resuelven tareas distintas.
- Las metodologías ofrecen vocabulario, no una verdad universal.
- Scope local no elimina la cascada.
- Variantes deben ser explícitas.
- Los nombres describen función y responsabilidad.
- Un override contextual suele indicar un contrato faltante.
¿Por qué .checkout-page .card h2 es más frágil que una variante del componente?
Respuesta
Porque depende de una estructura y página externas; mover la card o cambiar su markup altera el resultado sin modificar el componente.
Sistemas de diseño y Atomic Design conecta tokens, componentes, patrones y páginas.