Siempre he sostenido que una de las cosas más complejas de CSS es la organización. Salvo que estemos trabajando con cosas muy pequeñas, es muy sencillo que el código CSS se nos haga muy grande y se vuelva muy difícil de mantener y organizar.
La naturaleza de CSS hace que sea muy complejo de organizar. Cuando queremos diseñar algo, hay múltiples vertientes que queremos controlar; el aspecto visual en general, sí, pero eso implica muchas facciones: colores y tonalidades, que funcionen bien juntos, sombras, espacios, dimensiones, responsive, etc. Además, tenemos que intentar evitar que sea incoherente o que podamos añadir valores que no sean homogéneos (por ejemplo, dos tonalidades de color muy similares pero diferentes), o un tamaño de 30px
para un elemento y otro de 31px
para otro elemento.
¿Qué es una metodología CSS?
Se considera una metodología a una serie de métodos, consejos o forma de trabajar, que en el caso de seguir sus recomendaciones será mucho más fácil mantener y organizar tu código CSS. Existen metodologías más generalistas, otras que simplemente son convenciones para la sintaxis CSS y la forma de escribir clases y otras que se centran en como organizar los ficheros o la arquitectura de tu página.
Es importante tener claro que las metodologías buscan cumplir ciertos casos de uso que quizás no son exactamente los que nos vienen bien a nosotros, pero pueden existir programadores a los que les viene bien para sus casos de uso. Ten la mente abierta, observa bien los criterios que nos aconsejan y pruebalos antes de descartarlos o criticarlos.
Recuerda que no estás obligado a seguir una metodología concreta, simplemente son recomendaciones con las que puede ser más sencillo organizarte al escribir y mantener código, y depende de tu forma de trabajar que te guste más una que otra.
Metodologías CSS
En la siguiente tabla puedes ver una lista histórica de metodologías CSS que han conseguido cierta relevancia (algunos frameworks CSS han nacido a partir de dichas metodologías):
Año | Nombre de la metodología | Tipo | Popularidad | Más información |
---|---|---|---|---|
2009 | OOCSS (Object-oriented CSS) | CSS Semántico | ⭐⭐⭐ | GitHub |
2009 | BEM (Block Element Modifier) | CSS Semántico | ⭐⭐⭐⭐⭐ | BEM Info |
Soporte en Sass | ||||
2010 | Atomic CSS | CSS Atómico | ⭐⭐⭐ | Atomic CSS |
Atomizer, Tachyons, BassCSS | ||||
2011 | SMACSS (Scalable Modular Architecture CSS) | Arquitectura CSS | ⭐⭐⭐ | SMACSS |
2014 | SUITCSS | Arquitectura CSS | ⭐⭐ | SUITCSS |
2014 | CSS-in-JS | CSS desde Javascript | ⭐⭐⭐⭐ | CSS-in-JS |
Styled Components, Emotion, CSS Modules, WebComponents | ||||
2015 | RSCSS (Reasonable Standard for CSS) | CSS Semántico | ⭐ | RCSS |
2015 | ITCSS (Inverted Triangle CSS) | Arquitectura CSS | ⭐⭐ | ITCSS |
2016 | FLOCSS (File, Location, Organism, Component, State, Scope) | Arquitectura CSS | ⭐ | GitHub |
2017 | BEMIT (BEM + Inverted Triangle) | Arquitectura CSS | ⭐⭐ | BEMIT |
2017 | ABEM (Atomic Block Element Modifier) | CSS Semántico | ⭐ | ABEM |
2017 | Utility-First CSS | CSS Atómico | ⭐⭐⭐⭐⭐ | Utility First CSS |
TailwindCSS, UnoCSS | ||||
2018 | CUBE CSS | CSS Semántico | ⭐⭐ | CubeCSS |
De los anteriores, salvo por motivos históricos para comprender el movimiento de la industria de CSS o casos específicos, nos vamos a enfocar en lo que considero las vertientes más populares hoy en día: CSS Semántico (en general), BEM, CSS-in-JS y Utility-first CSS.
CSS Semántico
Probablemente, si estamos en fase de aprendizaje y queremos hacer una card, es muy posible que nuestro código termine siendo algo muy parecido a lo siguiente, que se denomina CSS semántico. Esta forma de escribir código CSS es muy natural y directa, aunque si uno no es cuidadoso, puede adquirir ciertos vicios y malas prácticas que acaben complicando el mantenimiento de tu código CSS a la larga:
<div class="card">
<div class="media">
<img class="image" src="manzdev.png" alt="Image">
</div>
<div class="info">
<h3 class="title">Títular de la card</h3>
<a class="button more" href="https://links.manz.dev/">Más info</a>
<a class="button author" href="https://manz.dev/">Su autor/a</a>
</div>
</div>
.card {
display: inline-block;
max-width: 300px;
border: 1px solid #000;
box-shadow: 0 0 8px #0006;
}
.card .image {
width: 100%;
}
.card .info {
padding: 1rem 2rem 2rem;
background: #fff;
text-align: center;
}
.card .info h3 {
font-family: Lexend, sans-serif;
font-size: 1.5rem;
margin-top: 0;
}
.card .info .button {
font-family: Lexend;
font-size: 0.75rem;
padding: 10px 15px;
border-radius: 4px;
text-decoration: none;
color: #fff;
}
.card .info .button.more { background: green; }
.card .info .button.more:hover { background: #00a600; }
.card .info .button.author { background: crimson; }
.card .info .button.author:hover { background: #ff1625; }
Ten muy en cuenta que, al utilizar selectores CSS con varios niveles de profundidad (para evitar seleccionar otros elementos que se llaman igual), eso hace que la especificidad CSS aumente y pueda producir efectos inesperados si no se sabe identificar.
BEM (Block Element Modifier)
Justo para evitar estos problemas de especificidad CSS, nace una de las metodologías CSS más populares, que aún hoy en día sigue siendo muy utilizada: BEM. A grandes rasgos, es una forma de nombrado de clases CSS que hace mucho más intuitivo su nombrado y organización, dividiendo todo en bloques, elementos y modificadores:
<div class="card">
<div class="card__media">
<img class="card__image" src="manzdev.png" alt="Image">
</div>
<div class="card__info">
<h3 class="card__title">Títular de la card</h3>
<a class="card__button card__button--more" href="https://links.manz.dev/">Leer más</a>
<a class="card__button card__button--author" href="https://manz.dev/">Su autor/a</a>
</div>
</div>
.card {
display: inline-block;
max-width: 300px;
border: 1px solid #000;
box-shadow: 0 0 8px #0006;
}
.card__image {
width: 100%;
}
.card__info {
padding: 1rem 2rem 2rem;
background: #fff;
text-align: center;
}
.card__title {
font-family: Lexend, sans-serif;
font-size: 1.5rem;
margin-top: 0;
}
.card__button {
font-family: Lexend;
font-size: 0.75rem;
padding: 10px 15px;
border-radius: 4px;
text-decoration: none;
color: #fff;
}
.card__button--more { background: green; }
.card__button--more:hover { background: #00a600; }
.card__button--author { background: crimson; }
.card__button--author:hover { background: #ff1625; }
El código CSS creado con BEM suele utilizar clases únicas que representan a un elemento concreto, reduciendo su especificidad (sólo es una clase) y evitando darle estilo a un elemento de forma inesperada (colisiones de nombres de clase) porque se llama de la misma forma aunque pertenece a otra parte de la página.
BEM es una metodología que es muy cómoda para utilizar junto a preprocesadores como Sass, ya que permite aprovechar su anidado CSS para generar clases únicas de BEM.
Utility-first CSS
Otra de las metodologías CSS más utilizadas hoy en día es el de las clases de utilidad (Utility-first CSS). Esta metodología, derivada de otra metodología denominada CSS atómico, aconseja crear clases de utilidad muy sencillas, con una o muy pocas propiedades CSS, que se apliquen en el HTML para dar estilo a los elementos. De esta manera, la forma de seleccionar elementos y darles estilo recae más en el HTML que en el CSS, algo que a priori resulta mucho más productivo:
<div class="inline-block max-w-xs border border-solid border-black shadow">
<div>
<img class="w-full" src="manzdev.png" alt="Image">
</div>
<div class="pt-4 pt-8 pb-8 bg-white text-center">
<h3 class="font-lexend text-2x1 mt-0">Títular de la card</h3>
<a class="font-lexend text-xs py-2 px-4 rounded no-underline
text-white bg-green-600"
href="https://links.manz.dev/">Leer más</a>
<a class="font-lexend text-xs py-2 px-4 rounded no-underline
text-white bg-red-600"
href="https://manz.dev/">Su autor/a</a>
</div>
</div>
.inline-block { display: inline-block; }
.max-w-xs { max-width: 300px; }
.border { border-width: 1px; }
.border-solid { border-style: solid; }
.border-black { border-color: #000; }
.shadow { box-shadow: 0 0 8px #0006; }
.w-full { width: 100%; }
.pt-4 { padding-top: 1rem; }
.px-8 { padding-left: 2rem; padding-right: 2rem; }
.pb-8 { padding-bottom: 2rem; }
.font-lexend { font-family: Lexend, sans-serif; }
.text-2x1 { font-size: 1.5rem; line-height: 2rem; }
.text-center { text-align: center; }
.mt-0 { margin-top: 0; }
.text-xs { font-size: 0.75rem; line-height: 1rem; }
.py-2 { padding-top: 8px; padding-bottom: 8px; }
.px-4 { padding-left: 15px; padding-right: 15px; }
.rounded { border-radius: 4px; }
.no-underline { text-decoration: none; }
.text-white { color: #fff; }
.bg-white { background: #fff; }
.bg-green-600 { background: green; }
.bg-green-600:hover { background: #00a600; }
.bg-red-600 { background: crimson; }
.bg-red-600:hover { background: #ff1625; }
Aunque a priori, el código CSS parece mucho menos entendible, la idea detrás de las clases de utilidad es que observando el HTML (y no el CSS) puedas tener una idea del estilo que se le da a ese elemento. Unido a que existen librerías, motores o frameworks (como TailwindCSS, por ejemplo) que ya tienen las clases predefinidas, sólo tendríamos que preocuparnos por aprenderlas y escribir las clases HTML en el lugar adecuado.
CSS-in-JS
Otra categoría muy popularizada en los últimos años, es la de CSS-in-JS, o lo que es lo mismo, manejar el CSS a través de Javascript. Con el incremento de la popularidad de React (librería donde «todo se hace desde Javascript»), gestionar estilos desde un fichero CSS no era demasiado cómodo, por lo que se populariza una metodología donde la idea es gestionar CSS desde un fichero Javascript, aprovechando las ventajas, flexibilidad y potencia de un lenguaje de programación y su control del DOM (o del Virtual DOM en el caso de React).
Observa este ejemplo, donde el HTML es idéntico, pero en lugar de utilizar un fichero .css
, escribimos código Javascript. Utilizamos la librería CSS-in-JS Emotion, concretamente su ayudante css
, para crear objetos de Javascript (ten en cuenta que existen multitud de librerías CSS-in-JS y cada una lo gestiona de formas variadas y diferentes, esto es un ejemplo muy simple):
<div class="card">
<div class="media">
<img class="image" src="manzdev.png" alt="Image">
</div>
<div class="info">
<h3 class="title">Títular de la card</h3>
<a class="button more" href="https://links.manz.dev/">Más info</a>
<a class="button author" href="https://manz.dev/">Su autor/a</a>
</div>
</div>
import { css } from "https://cdn.skypack.dev/@emotion/css";
// El método css crea una clase especial con el CSS indicado
// y devuelve una cadena de texto con esa nueva clase
const card = css`
display: inline-block;
max-width: 300px;
border: 1px solid #000;
box-shadow: 0 0 8px #0006;
& .image { width: 100%; }
`;
// Modificamos la clase "card" por la clase anterior
const cardElement = document.querySelector(".card");
cardElement.className = card;
// Creamos CSS para un botón que usaremos más tarde
const cssButton = `
font-family: Lexend;
font-size: 0.75rem;
padding: 10px 15px;
border-radius: 4px;
text-decoration: none;
color: #fff;
&.more { background: green; }
&.more:hover { background: #00a600; }
&.author { background: crimson; }
&.author:hover { background: #ff1625; }
`;
// Utilizamos composición para reutilizar el anterior
const info = css`
padding: 1rem 2rem 2rem;
background: #fff;
text-align: center;
& h3 {
font-family: Lexend, sans-serif;
font-size: 1.5rem;
margin-top: 0;
}
& .button {
${cssButton}
}
`;
// Modificamos la clase "info" por la clase anterior
const infoElement = document.querySelector(".info");
infoElement.className = info;
Mediante este método css
escribimos un css-k2dutc
) que reemplazaremos por card
. De esta forma, también se asegura que los nombres de clases son únicos y no aplicará estilos por error.
Este ejemplo didáctico tiene el código todo junto para ser más sencillo de entender. Sin embargo, en un ejemplo real podríamos utilizar módulos ECMAScript para separar cada bloque de código en ficheros separados y tenerlo todo mucho más organizado.
CSS Semántico (Moderno)
El CSS moderno tiene muchas características interesantes para hacer que el código sea mucho más entendible, breve y fácil de mantener, de modo que vamos a mostrar el código CSS semántico que vimos anteriormente, pero mejorándolo utilizando herramientas y features modernas de CSS:
<div class="card">
<div class="media">
<img class="image" src="manzdev.png" alt="Image">
</div>
<div class="info">
<h3 class="title">Títular de la card</h3>
<a class="button more" href="https://links.manz.dev/">Más info</a>
<a class="button author" href="https://manz.dev/">Su autor/a</a>
</div>
</div>
@scope (body) {
.card {
--font: Lexend, sans-serif;
--size: 19rem;
display: inline-block;
max-width: var(--size);
border: 1px solid #000;
box-shadow: 0 0 0.5rem #0006;
& .image { width: 100%; }
& .info {
padding: 1rem 2rem 2rem;
background: #fff;
text-align: center;
& .title {
font: 700 1.5rem var(--font);
margin-top: 0;
}
& .button {
font: 0.75rem var(--font);
padding: 0.7rem 1rem;
border-radius: 0.3rem;
text-decoration: none;
background: var(--bgcolor, steelblue);
color: #fff;
&.more { --bgcolor: green; }
&.author { --bgcolor: crimson; }
&:hover { background: color-mix(in srgb, var(--bgcolor), #fff 25%); }
}
}
}
}
Entre algunas de las características que aquí se utilizan, se encuentran las siguientes:
- ✨ Variables CSS: Reutiliza valores CSS para que el código sea más mantenible.
- ✨ Nesting CSS: Utiliza el anidado nativo para facilitar la lectura y escritura de CSS.
- ✨ Espacios de colores: Permite mezclar colores y reutilizar colores existentes.
- ✨ La regla @scope:
Permite delimitar el ámbito de acción de los estilos en el DOM.