variables css
Variables CSS: tu design system
Las custom properties son la base de cualquier design system profesional. Definen los valores fundamentales una vez y se reutilizan en todo el proyecto.
:root { /* COLORES */ --color-bg: #0d0d0d; --color-surface: #161616; --color-border: #2a2a2a; --color-text: #e8e8e8; --color-muted: #888888; --color-accent: #f0e040; --color-danger: #ff6b6b; --color-success: #6bffb8; /* TIPOGRAFÍA */ --font-body: 'Syne', sans-serif; --font-mono: 'DM Mono', monospace; --text-sm: 13px; --text-base: 15px; --text-lg: 18px; --text-xl: 24px; /* ESPACIADO */ --space-xs: 4px; --space-sm: 8px; --space-md: 16px; --space-lg: 24px; --space-xl: 40px; --space-2xl: 64px; /* BORDES */ --radius-sm: 2px; --radius-md: 4px; --border-default: 1px solid var(--color-border); } /* Uso: */ .card { background: var(--color-surface); border: var(--border-default); padding: var(--space-lg); border-radius: var(--radius-md); font-size: var(--text-base); }
Las variables CSS se pueden sobreescribir en contexto. Definir --color-accent: red dentro de .seccion-roja {} cambia el acento para todos los elementos dentro de esa sección, sin tocar el :root.
el box model
Box model: todo elemento es una caja
Antes de Flexbox y Grid necesitas entender cómo CSS calcula el tamaño de cada elemento. Este es el error más común entre principiantes.
Las 4 capas del box model
Cada capa añade espacio alrededor del contenido. Margin es el espacio exterior (no afecta el fondo). Padding es interior (hereda el fondo del elemento). Border rodea el padding.
Por qué box-sizing: border-box
/* SIN box-sizing: border-box (por defecto) */ .caja { width: 300px; padding: 20px; /* +40px */ border: 2px solid; /* +4px */ /* Ancho real: 300+40+4 = 344px ← SORPRESA */ } /* CON box-sizing: border-box (lo correcto) */ * { box-sizing: border-box; } .caja { width: 300px; padding: 20px; border: 2px solid; /* Ancho real: SIEMPRE 300px ← predecible */ }
Siempre añade * { box-sizing: border-box; } como primera regla de tu CSS. Sin excepción.
flexbox
Flexbox: alineamiento en un eje
Flexbox resuelve el alineamiento en una dimensión. Es tu herramienta para navbars, listas de cards, centrado vertical y distribución de elementos en fila o columna.
LOS DOS EJES DE FLEXBOX
→ eje principal (justify-content)
↕ eje cruzado (align-items)
justify-content
flex-start
elementos al inicio
flex-end
elementos al final
center
centrado
space-between
espacio entre
space-around
espacio alrededor
space-evenly
espacio idéntico
align-items:
flex-start center flex-end stretch baselinePropiedades de los hijos (flex items)
.flex-item { flex-grow: 1; /* cuánto crece (0 = no crece) */ flex-shrink: 0; /* 0 = no se encoge */ flex-basis: 200px; /* tamaño base */ /* Shorthand: */ flex: 1; /* grow:1, shrink:1, basis:0 */ flex: 0 0 200px; /* tamaño fijo */ align-self: flex-start; /* sobreescribe align-items del padre */ order: -1; /* cambia el orden visual */ }
Navbar con Flexbox
.navbar { display: flex; justify-content: space-between; align-items: center; padding: 0 40px; height: 64px; border-bottom: 1px solid var(--color-border); } .nav-logo { flex-shrink: 0; } /* no se encoge */ .nav-links { display: flex; gap: 32px; list-style: none; } .nav-actions { display: flex; gap: 12px; align-items: center; }
css grid
CSS Grid: layouts bidimensionales
Grid controla filas Y columnas simultáneamente. Para el layout general de la página, dashboards y cualquier estructura matricial. Regla: Flexbox para componentes, Grid para layouts.
grid-template-columns — patrones esenciales
/* Columnas fijas */ grid-template-columns: 280px 1fr; /* Tres columnas iguales */ grid-template-columns: repeat(3, 1fr); /* Responsive sin media queries (el más útil) */ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); /* Sidebar + contenido */ grid-template-columns: 240px 1fr; /* 12-column grid */ grid-template-columns: repeat(12, 1fr);
grid-template-areas — layouts con nombre
.layout { display: grid; grid-template-areas: "header header header" "sidebar main main" "footer footer footer"; grid-template-columns: 240px 1fr; grid-template-rows: 64px 1fr 48px; min-height: 100vh; } .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } .footer { grid-area: footer; }
Grid spanning — ocupar múltiples celdas
/* Ocupar múltiples columnas/filas */ .featured { grid-column: 1 / 3; /* columnas 1 y 2 */ grid-row: 1 / 3; /* filas 1 y 2 */ } /* Con span: */ .wide { grid-column: span 2; } .tall { grid-row: span 2; }
gap — espacio entre celdas
.grid { gap: 24px; /* igual en filas y columnas */ row-gap: 32px; /* solo entre filas */ column-gap: 16px; /* solo entre columnas */ gap: 32px 16px; /* filas columnas */ } /* place-items: shorthand de align-items + justify-items */ .grid-centered { place-items: center; }
responsive
Responsive: una web para todos
El 60% del tráfico global es móvil. Tu web debe verse bien en 375px y en 1920px. Los breakpoints definen cuándo cambia el layout.
✓ MOBILE-FIRST (recomendado)
/* Base: móvil */ .grid { display: flex; flex-direction: column; gap: 16px; } /* Tablet+ */ @media (min-width: 768px) { .grid { flex-direction: row; flex-wrap: wrap; } } /* Desktop */ @media (min-width: 1200px) { .grid { display: grid; grid-template-columns: repeat(3, 1fr); } }
DESKTOP-FIRST (evitar)
Escribes para desktop y sobreescribes con max-width. Genera más código y es más difícil de mantener.
/* Base: desktop (evitar) */ .grid { display: grid; grid-template-columns: repeat(3, 1fr); } /* Sobreescribir todo para móvil */ @media (max-width: 767px) { .grid { display: flex; flex-direction: column; /* más código, más cascada */ } }
| Nombre | Min-width | Dispositivos | Uso |
|---|---|---|---|
| xs | — | < 480px — Móvil pequeño | Estilos base |
| sm | 480px | Móvil grande | Primera expansión |
| md | 768px | Tablet | 2 columnas |
| lg | 1024px | Laptop | 3 columnas |
| xl | 1280px | Desktop | Layout completo |
El patrón moderno: auto-fit + minmax
Para grids de cards muchas veces no necesitas media queries:
/* 1 col en móvil, 2-3 en tablet, 3-4 en desktop — automático */ .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; }
pseudo-clases
Pseudo-clases y pseudo-elementos
Las pseudo-clases seleccionan elementos en estados específicos. Son la diferencia entre CSS estático y CSS que responde al usuario.
:hover
Mouse encima del elemento
.btn:hover { opacity: 0.85; }
:focus
Elemento recibe foco (teclado o clic)
input:focus {
border-color: var(--accent);
}
:active
Durante el clic (mientras se presiona)
.btn:active {
transform: scale(0.98);
}
:disabled
Elemento de formulario deshabilitado
button:disabled { opacity: 0.4; }
:checked
Checkbox o radio marcado
input:checked + label {
color: var(--accent);
}
:nth-child(n)
El n-ésimo hijo del padre
li:nth-child(odd) {
background: var(--surface2);
}
:first-child
El primer hijo de su padre
li:first-child { border-top: none; }
:last-child
El último hijo de su padre
li:last-child {
border-bottom: none;
}
:not(selector)
Todo elemento excepto el indicado
.card:not(.featured) {
opacity: 0.8;
}
:focus-visible
Foco de teclado (no de clic). Mejor accesibilidad que :focus
.btn:focus-visible {
outline: 2px solid var(--accent);
}
Pseudo-elementos
/* ::before y ::after — contenido generado */ .section-label::after { content: ''; flex: 1; height: 1px; background: var(--border); } .required::after { content: ' *'; color: var(--danger); } /* ::placeholder — estilo del placeholder */ input::placeholder { color: var(--muted); } /* ::selection — texto seleccionado */ ::selection { background: var(--accent); color: var(--bg); }
transiciones y animaciones
Movimiento: transiciones y @keyframes
El movimiento bien usado reduce la carga cognitiva. La regla: nunca más de 300ms para micro-interacciones, nunca movimiento sin propósito.
transition — cambios suaves de estado
.button { background: var(--surface); border: 1px solid var(--border); padding: 12px 24px; /* propiedad | duración | easing | delay */ transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease; } .button:hover { background: var(--accent); border-color: var(--accent); color: var(--bg); transform: translateY(-2px); } /* Easings más usados: */ /* ease | ease-in | ease-out | ease-in-out | linear */
@keyframes — animaciones de ciclo
@keyframes fadeIn { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } @keyframes spin { to { transform: rotate(360deg); } } .card { animation: fadeIn 0.4s ease-out both; } .dot { animation: pulse 2s ease-in-out infinite; } .loader { animation: spin 1s linear infinite; }
animation — propiedades y stagger
.elemento { animation-name: fadeIn; animation-duration: 0.4s; animation-timing-function: ease-out; animation-delay: 0s; animation-iteration-count: 1; /* o infinite */ animation-direction: normal; /* reverse | alternate */ animation-fill-mode: both; /* forwards | backwards */ /* Shorthand equivalente: */ animation: fadeIn 0.4s ease-out 0s 1 normal both; } /* Stagger: retrasar animaciones en una lista */ .card:nth-child(1) { animation-delay: 0ms; } .card:nth-child(2) { animation-delay: 80ms; } .card:nth-child(3) { animation-delay: 160ms; } /* Respetar preferencias de accesibilidad */ @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; } }
metodología bem
BEM: nombres de clase que escalan
BEM (Block, Element, Modifier) es la metodología de naming más usada en equipos. Elimina los conflictos de especificidad y hace el CSS predecible.
BLOCK
Un componente independiente. La "cosa" en sí. Tiene sentido por sí mismo.
ELEMENT
Parte de un bloque. No tiene sentido fuera de él. Doble underscore __
MODIFIER
Una variación del bloque o elemento. Doble guión --
Ejemplo completo — componente card
<!-- HTML --> <article class="card card--featured"> <img class="card__image" src="..." alt="..."> <div class="card__body"> <h2 class="card__title">Título</h2> <p class="card__description">Resumen...</p> <a class="card__link card__link--primary">Leer más</a> </div> </article> /* CSS */ .card { background: var(--surface); border: var(--border-default); } .card--featured { border-color: var(--accent); } .card__image { width: 100%; display: block; } .card__body { padding: 20px; } .card__title { font-size: 20px; font-weight: 700; } .card__link { display: inline-block; margin-top: 12px; } .card__link--primary { background: var(--accent); color: var(--bg); }
Especificidad plana: todas las clases BEM tienen la misma especificidad (0,1,0). Nunca necesitas !important para sobreescribir. Con CSS anidado (.nav .list .item a) la especificidad crece y se vuelve imposible de mantener.
ejercicio
Ejercicio: dashboard responsive
Construirás el layout completo de un dashboard de métricas con solo CSS moderno. Grid para el layout, Flexbox para los componentes, variables para los colores, responsive sin frameworks.
Dashboard de métricas responsive
Header, sidebar, grid de KPI cards, tabla de datos. Responsive: sidebar colapsa en móvil.
Design tokens
Define todas las variables CSS en :root — colores, fuentes, espaciado, radios. Este paso determina si tu CSS escala.
15 minLayout con Grid
Crea sidebar + área principal con grid-template-areas. Responsive: sidebar colapsa a display:none en móvil.
25 minKPI cards auto-fit
Grid auto-fit minmax(200px, 1fr) para las cards. Hover con transform + transition. Estados: normal, positivo, negativo.
25 minComponentes Flexbox
Flexbox para el header, para cada card, para las filas de tabla. :nth-child(even) para filas alternas.
25 minResponsive y animaciones
Media queries mobile-first. fadeIn en las cards con @keyframes. Prueba en DevTools: iPhone SE, iPad, Desktop.
30 minrecursos
Recursos de esta sesión
CSS Flexbox Froggy
24 niveles para dominar Flexbox jugando. Hazlos todos.
flexboxfroggy.com/#es
CSS Grid Garden
28 niveles para Grid. Imprescindible.
cssgridgarden.com/#es
CSS Tricks: Guía de Flexbox
La referencia visual más usada en el mundo para Flexbox.
css-tricks.com/snippets/css/a-guide-to-flexbox/
CSS Tricks: Guía de Grid
Lo mismo para Grid. Las dos abiertas en todo proyecto.
css-tricks.com/snippets/css/complete-guide-grid/
CSS Grid en 20 minutos — Midudev
El mejor video en español para arrancar con Grid.
youtube.com/watch?v=AxVXpS6PyRE