Buenas prácticas
Saber CSS es una cosa. Escribir CSS que otro desarrollador (o tú mismo en 3 meses) pueda entender y mantener es otra muy distinta. En esta lección vas a aprender las convenciones y patrones que usan los equipos profesionales para que el CSS no se convierta en un caos inmantenible.
Naming: BEM y por qué importa
Sin una convención de naming, acabas con clases como .red-box, .main-content-inner-wrapper-2 o .style1. BEM (Block, Element, Modifier) es la convención más extendida:
/* Block: componente independiente */
.card { }
/* Element: parte del bloque (separado con __) */
.card__title { }
.card__image { }
.card__body { }
.card__footer { }
/* Modifier: variación del bloque o elemento (separado con --) */
.card--featured { }
.card--compact { }
.card__title--large { }
<article class="card card--featured">
<img class="card__image" src="album.jpg" alt="Portada del disco">
<div class="card__body">
<h3 class="card__title">Khruangbin — A La Sala</h3>
<p class="card__price">32,90 €</p>
</div>
<div class="card__footer">
<button class="btn btn--primary">Añadir al carrito</button>
</div>
</article>
BEM te da tres superpoderes:
- Claridad: al ver
.card__titlesabes exactamente a qué componente pertenece. - Especificidad plana: todas son clases simples, misma especificidad, cero conflictos.
- Búsqueda fácil: buscar
.card__en tu editor te encuentra todo lo relacionado con la card.
Nesting nativo de CSS
En 2026 ya no necesitas Sass ni Less para anidar selectores. CSS lo hace de forma nativa:
/* Sin nesting */
.card { background: var(--color-surface); }
.card:hover { border-color: var(--color-brand); }
.card .card__title { font-size: 1.25rem; }
.card .card__title:hover { color: var(--color-brand); }
/* Con nesting nativo */
.card {
background: var(--color-surface);
&:hover {
border-color: var(--color-brand);
}
.card__title {
font-size: 1.25rem;
&:hover {
color: var(--color-brand);
}
}
}
El & representa al selector padre, exactamente como en Sass. Pero esto es CSS puro — sin preprocesadores, sin compilación.
/* Nesting con media queries */
.card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
@media (min-width: 768px) {
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
}
@media (min-width: 1024px) {
grid-template-columns: repeat(3, 1fr);
}
}
Las media queries dentro del bloque son mucho más legibles: ves todos los estilos de un componente juntos en lugar de repartidos por el archivo.
Organización de archivos CSS
Un solo archivo CSS gigante es inmantenible. Divide por responsabilidad:
styles/
├── reset.css /* Reset/normalize */
├── variables.css /* Custom properties */
├── base.css /* Estilos base: body, headings, links, etc. */
├── layout.css /* Grid del layout general */
├── components/
│ ├── card.css
│ ├── button.css
│ ├── navbar.css
│ ├── form.css
│ └── badge.css
├── utilities.css /* Clases utilitarias: .sr-only, .text-center */
└── main.css /* Importa todo en orden */
/* Orden de importación: de lo general a lo específico */
@import "reset.css";
@import "variables.css";
@import "base.css";
@import "layout.css";
@import "components/navbar.css";
@import "components/card.css";
@import "components/button.css";
@import "components/form.css";
@import "components/badge.css";
@import "utilities.css";
Reset y normalize
Cada navegador tiene estilos por defecto diferentes (user agent stylesheet). Un reset los neutraliza para que empieces desde una base consistente:
/* Reset moderno y minimalista */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
body {
min-height: 100dvh;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance;
}
p {
text-wrap: pretty;
}
a {
color: inherit;
text-decoration: inherit;
}
ul, ol {
list-style: none;
}
Este reset es más moderno que el clásico de Eric Meyer. Incluye text-wrap: balance para títulos, text-wrap: pretty para párrafos y 100dvh para la altura mínima.
Evitar !important
!important es el martillazo de CSS. Gana a todo, pero crea una escalada imposible de mantener:
/* ❌ Guerra de !important */
.title { color: blue !important; }
.card .title { color: red !important; }
#hero .card .title { color: green !important; } /* Hasta dónde llega esto? */
/* ✅ Solución: especificidad plana con clases */
.title { color: blue; }
.card-title { color: red; } /* Más específico por nombre, misma especificidad */
.hero-title { color: green; }
Los únicos usos legítimos de !important:
- Clases utilitarias que deben ganar siempre:
.sr-only { position: absolute !important; } - Sobrescribir estilos de librerías de terceros que no puedes modificar.
- El bloque de
prefers-reduced-motionpara forzar la desactivación de animaciones.
Clases utilitarias
Pequeñas clases de un solo propósito para cosas que se repiten constantemente:
/* Accesibilidad: visualmente oculto pero accesible para lectores de pantalla */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
/* Layout */
.flex { display: flex; }
.grid { display: grid; }
.hidden { display: none; }
/* Texto */
.text-center { text-align: center; }
.text-muted { color: var(--color-text-muted); }
.font-bold { font-weight: 700; }
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
Frameworks como Tailwind CSS llevan este concepto al extremo: todo son clases utilitarias. Es una aproximación válida y muy popular, pero primero necesitas entender CSS sin atajos para saber qué hace cada utilidad.
Errores comunes a evitar
1. Selectores demasiado específicos
/* ❌ Demasiado específico y frágil */
body > main > div.content > article:first-child > h2.title {
color: red;
}
/* ✅ Una clase directa */
.article-title {
color: red;
}
2. Valores mágicos
/* ❌ ¿Por qué 37px? ¿Qué pasa si cambia la fuente? */
.header {
height: 37px;
margin-top: 13px;
}
/* ✅ Valores con sentido */
.header {
padding-block: var(--space-4);
margin-block-start: var(--space-3);
}
3. Duplicar estilos
/* ❌ Repetición */
.btn-primary { background: #ff6b35; padding: 0.75rem 1.5rem; border-radius: 8px; }
.btn-danger { background: #ef4444; padding: 0.75rem 1.5rem; border-radius: 8px; }
/* ✅ Base + variantes */
.btn {
padding: 0.75rem 1.5rem;
border-radius: 8px;
}
.btn--primary { background: #ff6b35; }
.btn--danger { background: #ef4444; }
4. Usar IDs para estilos
/* ❌ ID tiene especificidad 1-0-0, difícil de sobrescribir */
#hero-section { padding: 4rem; }
/* ✅ Clase con nombre descriptivo */
.hero { padding: 4rem; }
Checklist de calidad CSS
Antes de dar por terminado tu CSS, revisa:
- ¿Todas las clases siguen una convención de naming consistente (BEM)?
- ¿Los colores y valores repetidos están en variables CSS?
- ¿Usas logical properties (
margin-block,padding-inline)? - ¿Hay algún
!importantque no debería estar? - ¿Los componentes son reutilizables o están acoplados a una página específica?
- ¿Hay un bloque
prefers-reduced-motionsi usas animaciones? - ¿El layout funciona en móvil sin scroll horizontal?
- ¿Los textos tienen contraste suficiente sobre sus fondos?
Refactoriza el CSS de Vinyl Paradise
Toma todo el CSS que has ido escribiendo para Vinyl Paradise a lo largo de la sección y refactorízalo siguiendo buenas prácticas:
- Aplica naming BEM a todas las clases
- Usa nesting nativo de CSS para agrupar selectores relacionados
- Extrae todos los colores y valores repetidos a variables CSS en
:root - Añade el reset moderno al principio
- Convierte las media queries a nesting dentro de cada componente
- Sustituye propiedades físicas (
margin-top) por lógicas (margin-block-start) - Elimina cualquier
!importanty resuelve el conflicto de especificidad correctamente - Organiza el CSS en secciones lógicas con comentarios
lightbulb Pistas
Empieza creando las variables en :root. Luego renombra las clases a BEM. Después convierte los selectores anidados con &. Al final, mueve las media queries dentro de sus componentes. El CSS debería leerse como una historia: variables → reset → base → componentes → utilidades.