Arquitectura CSS en proyectos reales
En una web de tres archivos da igual cómo escribas el CSS. En un proyecto real —decenas de páginas, varias personas editando— el orden es supervivencia. La receta más sencilla y efectiva: organizar por capas.
| Capa | Contiene | Ejemplo |
|---|---|---|
| Reset/base | Normalizar el navegador y definir tokens | :root, * { box-sizing }, tipografía base |
| Layout | El esqueleto de la página | cabecera, rejillas principales, pie |
| Componentes | Piezas independientes y reutilizables | .btn, .card, .form-field |
| Utilidades | Ajustes puntuales de una sola propiedad | .text-center, .mt-0 |
/* ========== 1. TOKENS Y BASE ========== */
:root { /* ... */ }
/* ========== 2. LAYOUT ========== */
/* ========== 3. COMPONENTES ========== */
/* ========== 4. UTILIDADES ========== */
1.1 · Nombres que no explotan: BEM ligero
No necesitas la ceremonia completa de BEM, pero sí su idea central: bloque__elemento--modificador. El nombre describe estructura, no apariencia ni posición:
.card__titulo✔️ — «el título dentro de tarjeta»..card--destacada✔️ — «la variante destacada de tarjeta»..margen-izquierdo-rojo❌ — describe pintura; mañana será azul y estará a la derecha.
1.2 · Orden interno de propiedades
Dentro de cada regla, un criterio fijo evita discusiones y hace los diffs legibles: primero caja y layout (display, position, tamaño), después visual (colores, bordes, sombras) y al final tipografía y detalles.
.tarjeta {
/* 1. caja y posición */
display: grid;
position: relative;
padding: 24px;
/* 2. visual */
background: #fff;
border-radius: 14px;
box-shadow: 0 8px 22px rgba(0, 0, 0, .12);
/* 3. tipografía y transiciones */
font-size: 1rem;
transition: transform .3s ease;
}
Componentes reutilizables
Un componente CSS es una clase que funciona igual dondequiera que la pegues: botones, tarjetas, campos de formulario. La técnica clave es clase base + modificadores:
.btn {
padding: .6em 1.2em;
border-radius: 999px;
font-weight: 600;
transition: transform .25s ease, box-shadow .25s ease;
}
.btn--primario { background: var(--primario); color: #fff; }
.btn--fantasma { background: transparent; border: 2px solid var(--primario); }
.btn--pequeno { font-size: .85rem; }
/* uso: <button class="btn btn--primario"> */
Cambias el radio del botón en .btn y las tres variantes se actualizan.
Cada modificador solo declara lo que difiere.
2.1 · Formularios que dan gusto
.form-field input {
width: 100%;
padding: .7em 1em;
border: 1px solid #ccc;
border-radius: 10px;
}
.form-field input:focus-visible {
outline: 3px solid var(--foco);
outline-offset: 2px;
}
2.2 · Composición sobre duplicación
Necesitas una tarjeta igual pero con borde dorado. Antes de escribir CSS nuevo: ¿puede ser un modificador? ¿Puede heredar variables? Casi siempre sí.
.card-oro {
border-radius: 14px;
padding: 20px;
box-shadow: ...;
border: 2px solid gold;
}
.card--oro {
border: 2px solid gold;
}
/* el resto ya lo aporta .card */
aside div p span).
Una clase explícita sobrevive a cualquier reorganización del markup.Detalles de calidad y accesibilidad
3.1 · Estados completos en interactivos
Un botón profesional responde a todos sus estados, no solo al hover:
.btn:hover { transform: translateY(-2px); }
.btn:focus-visible { outline: 3px solid var(--foco); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
:focus-visible en vez de :focus: muestra
el anillo solo cuando se navega con teclado. Y jamás hagas outline: none sin
ofrecer otro indicador — quien navega con Tab quedaría ciego a su posición.3.2 · Contraste y movimiento
- Contraste mínimo WCAG AA: texto normal 4.5:1; grande (≥24px) 3:1. Las DevTools lo calculan en el inspector de color.
- Respeta las preferencias de movimiento: hay gente a la que las animaciones le provocan mareo. Es una media query:
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}
/* único caso donde !important es razonable:
ganarle a cualquier especificidad ajena */
3.3 · Auditoría express antes de entregar
- Navega la página completa solo con Tab: ¿sabes dónde estás siempre?
- Prueba en móvil, tablet y escritorio (modo dispositivo).
- Sube el zoom al 200 %: ¿sigue siendo usable?
- Revisa la consola: cero errores y cero recursos rotos (404).
El proyecto final, paso a paso
Vas a construir «mi-portafolio.html»: una página completa que presenta quién eres y tus mejores trabajos. Es tu carta de presentación como desarrollador/a y el examen práctico de este curso.
4.1 · El plan de ataque
- Estructura semántica: header + nav + main + footer, secciones con
<section>e ids anclables. - Tokens: paleta, espaciados y radios en
:root. - Layout mobile-first: una columna por defecto; media queries
min-widthpara ampliar. - Componentes: botón, tarjeta de proyecto y campo de formulario como clases reutilizables.
- Motion: transición en interactivos + una animación de entrada sutil.
- Auditoría: la checklist de la lección 3, ítem por ítem.
4.2 · Esqueleto recomendado
<header> logo + nav (flex, sticky)
<main>
<section id="inicio"> hero con degradado
<section id="proyectos"> grid auto-fit de tarjetas
<section id="contacto"> formulario accesible
</main>
<footer> columnas con grid + copyright
4.3 · Cómo se evalúa
La Parte B del examen valida automáticamente los ocho criterios de graduación: viewport, semántica, variables, layout moderno, responsive, interactividad animada, acabado visual y limpieza del código. Aprueba con 7/8… pero apunta al 8/8.
✍️ Los 12 ejercicios del bloque
Crea la carpeta css-b4/: los ejercicios construyen, pieza a pieza, el
portafolio del proyecto final.
1 Reset y base
Monta el punto de partida: box-sizing: border-box global, márgenes a cero
y tipografía base sobre el elemento raíz del documento para las variables.
Ver solución
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, sans-serif; }
:root { /* tokens aquí */ }
2 Sistema de tokens
Define en :root cinco variables: dos colores, un color de foco, un
espaciado y un radio de borde. Úsalas todas al menos una vez.
Ver solución
:root {
--primario: #6c5ce7;
--texto: #22223b;
--foco: #00cec9;
--espacio: 24px;
--radio: 14px;
}
3 Cabecera sticky responsive
Cabecera pegajosa con flexbox: marca a la izquierda, nav a la derecha, centrado vertical y fondo sólido.
Ver solución
.cabecera {
position: sticky; top: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--espacio);
}
4 Botón base + variantes
Crea .btn y sus modificadores --primario,
--fantasma y --pequeno sin repetir ninguna propiedad común.
Ver solución
Exactamente el patrón de la lección 2: lo común en .btn, lo distinto en cada
--modificador.
5 Rejilla de proyectos
Las tarjetas de proyecto en grid autorresponsive: mínimo 220px, separación de 20px, sin una sola media query.
Ver solución
.proyectos {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
6 Formulario accesible
Estiliza inputs y textarea del formulario de contacto, con anillo de foco visible
mediante :focus-visible.
Ver solución
input, textarea {
width: 100%;
padding: .7em 1em;
border: 1px solid #ccc;
border-radius: var(--radio);
}
input:focus-visible, textarea:focus-visible {
outline: 3px solid var(--foco);
outline-offset: 2px;
}
7 Estados completos
Añade a .btn los cuatro estados: hover elevado, focus-visible con anillo,
active hundido y disabled atenuado.
Ver solución
.btn:hover { transform: translateY(-2px); }
.btn:focus-visible { outline: 3px solid var(--foco); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
8 Hero con degradado
Portada a pantalla casi completa con degradado diagonal, titular grande y botón que ancla a #proyectos.
Ver solución
.hero {
min-height: 70vh;
display: grid;
place-content: center;
text-align: center;
background: linear-gradient(160deg, var(--primario), #00cec9);
color: #fff;
}
9 Animación de entrada
Los elementos del hero aparecen deslizándose hacia arriba al cargar la página:
keyframes entrar aplicada con un pequeño delay escalonado.
Ver solución
@keyframes entrar {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: none; }
}
.hero > * {
animation: entrar .6s ease-out backwards;
}
.hero > *:nth-child(2) { animation-delay: .15s; }
.hero > *:nth-child(3) { animation-delay: .3s; }
10 Footer en columnas
Pie de página con tres columnas en escritorio que colapsan a una en móvil, usando mobile-first (una columna base + min-width).
Ver solución
.pie-grid {
display: grid;
gap: 24px;
}
@media (min-width: 700px) {
.pie-grid { grid-template-columns: repeat(3, 1fr); }
}
11 Respeto al motion reducido
Añade la media query prefers-reduced-motion de la lección 3 para
desactivar animaciones y transiciones a quien lo solicite.
Ver solución
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: .01ms !important;
transition-duration: .01ms !important;
}
}
12 🏆 PROYECTO FINAL: «mi-portafolio.html»
Integra los ejercicios anteriores en una página única y pulida. Requisitos de graduación:
- Semántica completa:
header,nav,main,footer - Tokens en
:rootusados convar() - Flex/Grid en el layout + media query
min-width - Estados interactivos con transición
- Sombras o degradados, y cero estilos inline ni forzados con prioridad artificial
Es el reto del laboratorio del examen: apruébalo y gradúate en CSS.
📝 Examen del Bloque 4
Dos partes: test teórico autoevaluable (mínimo 70 %) y reto práctico final con checklist de graduación.
Parte B · Reto práctico final
Construye «mi-portafolio.html» (ejercicio 12) sin mirar soluciones y valídalo contra la checklist de graduación. Mínimo para aprobar: 7 de 8 casillas.
Cumplidos: 0 / 8