Flexbox:
domina el eje
Flexbox resuelve el 80% del layout cotidiano. Es unidimensional — trabaja en fila o columna. Entenderlo completamente te da superpoderes de distribución de espacio.
El modelo mental de Flexbox
Flexbox opera sobre dos ejes: el eje principal (main axis) y el eje cruzado (cross axis). Todo lo demás es consecuencia de dónde apuntan esos ejes.
Las propiedades esenciales
/* ── En el CONTENEDOR PADRE ─────────────────── */ .contenedor { display: flex; /* activa flexbox */ /* Dirección del eje principal */ flex-direction: row; /* → fila (default) */ flex-direction: column; /* ↓ columna */ flex-direction: row-reverse; /* ← fila invertida */ /* Distribución en el EJE PRINCIPAL */ justify-content: flex-start; /* al inicio */ justify-content: center; /* centrado */ justify-content: flex-end; /* al final */ justify-content: space-between;/* máximo espacio entre */ justify-content: space-around; /* espacio igual alrededor */ justify-content: space-evenly; /* espacio perfectamente igual */ /* Alineación en el EJE CRUZADO */ align-items: flex-start; /* arriba (en row) */ align-items: center; /* centrado vertical */ align-items: flex-end; /* abajo */ align-items: stretch; /* estira para llenar (default) */ align-items: baseline; /* alinea líneas base de texto */ /* Salto de línea */ flex-wrap: nowrap; /* no rompe (default) */ flex-wrap: wrap; /* los hijos bajan de línea */ gap: 16px; /* espacio entre hijos */ gap: 16px 24px; /* row-gap column-gap */ } /* ── En los HIJOS ───────────────────────────── */ .hijo { flex-grow: 1; /* crece para llenar espacio disponible */ flex-shrink: 0; /* no se encoge (0 = rígido) */ flex-basis: 200px; /* tamaño base antes de grow/shrink */ /* Shorthand: grow shrink basis */ flex: 1 1 200px; /* grow shrink basis */ flex: 1; /* grow=1, shrink=1, basis=0 (más común) */ align-self: center; /* override del align-items del padre */ order: 2; /* cambia el orden visual */ }
Casos de uso reales en portfolios
/* ── Navbar: logo izquierda, links derecha ── */ .navbar { display: flex; justify-content: space-between; align-items: center; padding: 16px 40px; } /* ── Centrar absolutamente cualquier cosa ── */ .hero { display: flex; justify-content: center; align-items: center; min-height: 100vh; /* pantalla completa */ flex-direction: column; /* texto apilado */ gap: 24px; } /* ── Grid de cards que se adaptan ── */ .card-grid { display: flex; flex-wrap: wrap; gap: 20px; } .card { flex: 1 1 280px; /* min 280px, crece para llenar */ } /* ── Footer: tres columnas ── */ .footer { display: flex; justify-content: space-between; align-items: flex-start; gap: 40px; flex-wrap: wrap; /* en móvil se apila */ }
Para centrar algo perfectamente en horizontal y vertical: display:flex; justify-content:center; align-items:center. Es la solución más elegante al eterno problema de "¿cómo centro esto?"
Recursos de referencia
- 1En tu portfolio de M01, convierte el
<header>en un navbar Flexbox: logo izquierda, nav links derecha, perfectamente alineados verticalmente. - 2Crea una sección
.herocon Flexbox que centre todo su contenido vertical y horizontalmente usandomin-height: 100vh. - 3Convierte tu grilla de proyectos en
flex-wrap: wrapconflex: 1 1 280pxen cada tarjeta. Reduce la ventana del navegador para ver cómo se adaptan. - 4Usa el Demo interactivo de arriba para explorar cada propiedad antes de escribirla en tu CSS.
CSS Grid:
el tablero infinito
Grid es bidimensional: controla filas Y columnas al mismo tiempo. Es el sistema más poderoso que tiene CSS y la razón por la que ya no necesitamos frameworks de layout.
Grid vs Flexbox: cuándo usar cuál
| Situación | Usa Flexbox | Usa Grid |
|---|---|---|
| Navbar / barra de herramientas | ✓ Perfecto | — |
| Centrar un elemento | ✓ Más simple | También funciona |
| Galería de imágenes | — | ✓ Ideal |
| Layout de página completo | — | ✓ Perfecto |
| Cards en fila que "wrappean" | ✓ Con flex-wrap | ✓ auto-fill/fit |
| Layouts editoriales complejos | — | ✓ Insuperable |
Demo interactivo · Grid en vivo
Sintaxis completa de Grid
/* ── CONTENEDOR ─────────────────────────────── */ .grid { display: grid; /* Columnas: la propiedad más importante */ grid-template-columns: 200px 1fr 200px; /* sidebar - main - sidebar */ grid-template-columns: repeat(3, 1fr); /* 3 columnas iguales */ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); /* ↑ El patrón más poderoso: mínimo 280px, máximo 1fr */ /* auto-fill crea tantas columnas como quepan */ /* Filas */ grid-template-rows: 80px 1fr auto; /* header - contenido - footer */ grid-auto-rows: 200px; /* filas implícitas (automáticas) */ /* Espaciado */ gap: 20px; /* rows y columns */ row-gap: 16px; column-gap: 24px; /* Alineación de todos los items */ justify-items: start | center | end | stretch; align-items: start | center | end | stretch; } /* ── ITEM: posicionamiento explícito ────────── */ .item-especial { /* Columnas: ocupa del 1 al 3 (span 2 columnas) */ grid-column: 1 / 3; /* de línea 1 a línea 3 */ grid-column: span 2; /* ocupa 2 columnas */ grid-column: 1 / -1; /* de inicio a fin (ancho completo) */ /* Filas */ grid-row: 1 / 3; /* ocupa 2 filas */ } /* ── TEMPLATE AREAS: layout semántico ──────── */ .pagina { display: grid; grid-template-areas: "header header header" "sidebar main main " "footer footer footer"; grid-template-columns: 240px 1fr 1fr; grid-template-rows: 80px 1fr 60px; } .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } .footer { grid-area: footer; }
Subgrid permite que un hijo de un grid herede las líneas de columna/fila del padre. Resuelve el problema histórico de alinear contenido anidado con el grid externo. grid-template-columns: subgrid
Inspiración visual: layouts con Grid
Los mejores sitios creativos usan Grid para layouts que Flexbox no puede hacer. Fuente: Unsplash
- 1Reemplaza el Flexbox de tu grilla de proyectos por CSS Grid:
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)). Observa cómo se comporta al cambiar el tamaño de la ventana. - 2Haz que el primer proyecto ocupe el ancho completo:
grid-column: 1 / -1. Ajusta suaspect-ratio: 21/9. - 3Crea el layout completo de tu página usando grid-template-areas: header, main y footer.
- 4Juega en Grid Garden — al menos 15 niveles.
Layout combinado:
Grid + Flex
La realidad es que Grid y Flexbox se usan juntos. Grid para la estructura macro de la página, Flex para los componentes internos. Esta es la arquitectura de cualquier sitio moderno.
El patrón de los tres niveles
Piensa en cualquier página web en tres niveles de layout:
/* ── NIVEL 1: Macro layout (GRID) ───────────── */ body { display: grid; grid-template-rows: auto 1fr auto; /* header / main / footer */ min-height: 100vh; } /* ── NIVEL 2: Secciones (GRID) ──────────────── */ .proyectos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; } /* ── NIVEL 3: Componentes internos (FLEX) ───── */ .proyecto-card { display: flex; flex-direction: column; /* imagen arriba, texto abajo */ } .card-footer { display: flex; justify-content: space-between; align-items: center; margin-top: auto; /* empuja al fondo de la card */ } .navbar { display: flex; /* nivel 3: el nav es flex */ justify-content: space-between; align-items: center; } /* position: relative/absolute para overlays ── */ .card-imagen-wrap { position: relative; overflow: hidden; } .card-overlay { position: absolute; inset: 0; /* top:0 right:0 bottom:0 left:0 */ background: rgba(0,0,0,.7); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity .3s; } .card-imagen-wrap:hover .card-overlay { opacity: 1; }
Usa Grid cuando piensas en filas Y columnas al mismo tiempo. Usa Flex cuando piensas en una sola dirección (fila o columna). En la duda, usa Grid — siempre es más flexible.
- 1Diagrama en papel la arquitectura de tu portfolio: ¿qué es Grid macro? ¿Qué secciones usan Grid? ¿Qué componentes usan Flex?
- 2Implementa el layout con la estructura de tres niveles. El
bodycomo Grid, las secciones como Grid o Flex según corresponda. - 3Añade el efecto
overlayhover a tus tarjetas de proyecto usandoposition: relative/absolute.
Mobile-first:
el principio
Diseñar para móvil primero no es una restricción — es una disciplina que te obliga a priorizar lo esencial. El 60%+ del tráfico web global viene de dispositivos móviles.
¿Por qué mobile-first?
El enfoque tradicional era diseñar para desktop y luego "reducir" para móvil. El problema: cuando empiezas grande y reduces, sueles ocultar cosas en lugar de repensar la experiencia. Mobile-first invierte esto: empieza con el contexto más restringido y enriquece hacia pantallas grandes.
| Enfoque | Desktop-first | Mobile-first ✓ |
|---|---|---|
| Punto de partida | Pantalla grande | Pantalla pequeña |
| Dirección | max-width en media queries | min-width en media queries |
| Comportamiento | Ocultar para móvil | Agregar para desktop |
| Performance | CSS pesado en móvil | CSS ligero en móvil |
| UX | Pensado para mouse | Pensado para touch |
/* ── MOBILE FIRST: el CSS base es para móvil ── */ /* Base (móvil, ~320px-767px): una columna */ .proyectos { display: grid; grid-template-columns: 1fr; /* 1 columna */ gap: 16px; } .navbar { flex-direction: column; /* links apilados en móvil */ align-items: flex-start; } /* Tablet (≥768px): dos columnas */ @media (min-width: 768px) { .proyectos { grid-template-columns: repeat(2, 1fr); gap: 20px; } .navbar { flex-direction: row; /* horizontal en tablet+ */ } } /* Desktop (≥1200px): tres columnas */ @media (min-width: 1200px) { .proyectos { grid-template-columns: repeat(3, 1fr); gap: 28px; } }
- 1Abre DevTools → Device Toolbar (ícono de móvil) → selecciona iPhone 12. Tu portfolio debe verse bien ahí.
- 2Reescribe tu CSS empezando por móvil: una columna, texto más grande, padding suficiente para dedos.
- 3Añade breakpoints con
min-widthpara tablet (768px) y desktop (1200px). Nunca usesmax-widthpara esto.
Media Queries:
puntos de quiebre
Las media queries son el mecanismo que permite a CSS responder al contexto del usuario: tamaño de pantalla, preferencias de movimiento, tema oscuro, resolución. Son condiciones lógicas.
Sintaxis y tipos
/* ── POR ANCHO (las más usadas) ─────────────── */ @media (min-width: 768px) { /* tablet y desktop */ } @media (min-width: 1024px) { /* desktop */ } @media (min-width: 1440px) { /* pantallas grandes */ } /* Rango: solo para un tamaño específico */ @media (min-width: 768px) and (max-width: 1023px) { /* solo tablet */ } /* ── POR PREFERENCIAS DEL USUARIO ───────────── */ /* Dark mode (lo vimos en M01) */ @media (prefers-color-scheme: dark) { :root { --color-bg: #0a0a0f; } } /* Reducir movimiento (accesibilidad CRÍTICA) */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } } /* Alta resolución (Retina) para imágenes 2x */ @media (min-resolution: 2dppx) { .logo { background-image: url('logo@2x.png'); } } /* ── CONTAINER QUERIES (2024, nuevo!) ────────── */ /* En vez de pantalla, responde al contenedor padre */ .card-container { container-type: inline-size; } @container (min-width: 400px) { .card { display: grid; grid-template-columns: 120px 1fr; /* imagen lateral cuando hay espacio */ } }
Las Media Queries responden al viewport (pantalla). Las Container Queries responden al contenedor padre. Un componente puede ahora adaptarse según el espacio que ocupa, no según el tamaño de pantalla. Soportado en todos los navegadores modernos desde 2023.
Breakpoints recomendados
| Nombre | Valor | Dispositivos típicos |
|---|---|---|
| Base (móvil) | 0px — 767px | iPhone, Android pequeños/medianos |
| sm (tablet) | 768px+ | iPad, tablets, móviles grandes |
| md (desktop pequeño) | 1024px+ | Laptops, iPads landscape |
| lg (desktop) | 1280px+ | Monitores, MacBooks |
| xl (pantalla grande) | 1536px+ | Monitores 27"+ |
Unidades fluidas
y clamp()
Las unidades relativas y las funciones matemáticas de CSS permiten crear layouts y tipografías que se adaptan fluidamente sin media queries. El futuro del responsive design.
El universo de unidades CSS
| Unidad | Relativa a | Cuándo usarla |
|---|---|---|
px | Píxeles físicos | Bordes, sombras, valores fijos pequeños |
rem | font-size del <html> (16px default) | Tipografía, espaciado — la más recomendada |
em | font-size del elemento padre | Padding/margin relativos al texto |
% | El contenedor padre | Anchos fluidos, aspect ratios |
vw | Ancho del viewport | Tipografía grande, secciones full-width |
vh | Alto del viewport | Secciones full-screen (min-height: 100vh) |
dvh | Viewport dinámico (con barras de navegación) | Móvil: reemplaza vh para evitar saltos |
fr | Fracción del espacio disponible en Grid | Solo en Grid |
ch | Ancho del carácter "0" | Ancho de línea de texto (60-75ch ideal) |
/* ── clamp(min, ideal, max) ──────────────────── */ /* El valor más poderoso del CSS moderno */ h1 { /* No menos de 32px, idealmente 5vw, no más de 80px */ font-size: clamp(32px, 5vw, 80px); /* Se adapta fluidamente sin media queries */ } h2 { font-size: clamp(24px, 3.5vw, 48px); } p { font-size: clamp(15px, 1.2vw, 18px); } /* ── min() y max() ───────────────────────────── */ .container { /* El menor de los dos: 100% o 1200px */ width: min(100%, 1200px); margin: 0 auto; } .hero-title { /* Al menos 48px (aunque la pantalla sea pequeña) */ font-size: max(48px, 8vw); } /* ── Espaciado fluido ────────────────────────── */ .section { padding: clamp(48px, 8vw, 120px) clamp(20px, 5vw, 80px); /* Padding que escala con la pantalla, sin media queries */ } /* ── Ancho máximo de lectura ─────────────────── */ .text-content { max-width: 65ch; /* 65 caracteres = legibilidad óptima */ margin: 0 auto; } /* ── dvh: el vh que funciona en móvil ───────── */ .hero { min-height: 100dvh; /* dinámico: respeta barra del navegador */ /* fallback para navegadores viejos: */ min-height: 100vh; min-height: 100dvh; }
Calcular los valores de clamp puede ser complicado. Usa clamp.font-size.app — introduces el tamaño en móvil y desktop y te da el valor clamp exacto.
Tipografía web:
el diseño invisible
El 95% del diseño web es tipografía. Una fuente elegida con intención y configurada correctamente puede transformar completamente la personalidad de un proyecto.
Cómo cargar fuentes en web
/* ── OPCIÓN 1: Google Fonts (link en HTML) ──── */ <!-- En el <head> de tu HTML --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2? family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,800 &family=Playfair+Display:ital,wght@1,300 &display=swap" rel="stylesheet"> /* ── OPCIÓN 2: @font-face local (más control) ─ */ @font-face { font-family: 'MiFuente'; src: url('fonts/mifuente.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; /* muestra fallback mientras carga */ } /* ── PROPIEDADES tipográficas ─────────────────── */ body { font-family: 'Bricolage Grotesque', sans-serif; font-size: 16px; /* base */ line-height: 1.7; /* sin unidad: relativo al font-size */ letter-spacing: -0.01em; /* tracking ligeramente condensado */ font-weight: 400; /* regular */ font-optical-sizing: auto; /* para variable fonts */ } h1, h2, h3 { font-family: 'Bricolage Grotesque', sans-serif; font-weight: 800; line-height: 1.0; /* más ajustado en títulos grandes */ letter-spacing: -0.03em; /* tracking negativo en display type */ } /* ── VARIABLE FONTS: una fuente, infinitos pesos ─ */ h2 { font-variation-settings: 'wght' 750, /* peso variable (entre 100-900) */ 'wdth' 110; /* ancho variable */ } /* Animar el peso en hover con variable fonts */ a:hover { font-variation-settings: 'wght' 800; transition: font-variation-settings 0.3s; }
Escala tipográfica perfecta
Una escala tipográfica es una progresión de tamaños armoniosa. Las más usadas siguen razones matemáticas como la proporción áurea (1.618) o la quinta mayor (1.5).
/* Escala perfecta × 1.25 (Major Third) */ :root { --text-xs: 0.64rem; /* ~10px */ --text-sm: 0.8rem; /* ~13px */ --text-base: 1rem; /* 16px — base */ --text-lg: 1.25rem; /* ~20px */ --text-xl: 1.563rem; /* ~25px */ --text-2xl: 1.953rem; /* ~31px */ --text-3xl: 2.441rem; /* ~39px */ --text-4xl: 3.052rem; /* ~49px */ /* Con clamp para que sea fluida: */ --text-hero: clamp(3rem, 8vw, 8rem); } /* Genera la tuya: typescale.com */
Fuentes recomendadas para proyectos creativos
- 1Ve a Google Fonts. Elige 2 fuentes: una display (para títulos) y una para cuerpo. Descárgalas o genera el
<link>. - 2En Typescale.com, configura tu escala tipográfica. Exporta las variables CSS y agrégalas a tu
:root. - 3Usa clamp() para que los títulos principales sean fluidos entre móvil y desktop.
- 4Ajusta
line-height,letter-spacingymax-width: 65chen párrafos para máxima legibilidad.
Color y gradientes:
atmósfera visual
El color en CSS va mucho más allá de los hexadecimales. Gradientes, mezclas, transparencias y el nuevo espacio oklch te dan control total sobre la paleta.
Sistemas de color en CSS
/* ── FORMATOS DE COLOR ────────────────────────── */ color: #c84b2f; /* Hex: compacto, más usado */ color: rgb(200, 75, 47); /* RGB: útil con variables */ color: rgba(200, 75, 47, 0.5); /* RGBA: con transparencia */ color: hsl(12, 62%, 48%); /* HSL: más intuitivo (matiz, sat, light) */ color: hsl(12 62% 48% / 0.5); /* HSL con alpha (sintaxis moderna) */ /* ── oklch: el futuro del color en CSS ──────── */ /* Perceptualmente uniforme: L=lightness, C=chroma, H=hue */ color: oklch(0.65 0.18 30); /* rojo cálido */ color: oklch(0.80 0.14 160); /* verde menta */ /* oklch garantiza que el 50% de lightness es visualmente igual en todos los colores */ /* ── GRADIENTES ──────────────────────────────── */ background: linear-gradient( 135deg, #0a0a14 0%, #1a0a2e 100% ); background: radial-gradient( ellipse at 80% 50%, rgba(110, 231, 183, 0.3) 0%, transparent 60% ); /* Gradiente cónico (para círculos de color) */ background: conic-gradient( from 0deg, #6ee7b7, #818cf8, #fb923c, #6ee7b7 ); /* Múltiples gradientes apilados */ background: radial-gradient(circle at 20% 80%, rgba(129,140,248,.3) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(110,231,183,.2) 0%, transparent 50%), #0c0c10; /* ── MIX-BLEND-MODE: para efectos creativos ─── */ .overlay { mix-blend-mode: screen; /* mezcla con lo que hay debajo */ mix-blend-mode: multiply; /* multiplica colores */ mix-blend-mode: overlay; /* contraste dramático */ }
Paletas de color: recursos
Efectos visuales
con CSS puro
CSS moderno tiene superpoderes visuales que muchos no conocen: clip-path, backdrop-filter, mask-image y más. Estos efectos son los que hacen que un sitio parezca obra de arte.
/* ── clip-path: formas creativas ─────────────── */ .hero-diagonal { clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%); /* Diagonal en el fondo: top izq, top der, bottom der, bottom izq */ } .hexagono { clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); } /* Animable! */ .btn:hover { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); transition: clip-path .5s cubic-bezier(.77,0,.175,1); } /* ── backdrop-filter: vidrio difuminado ──────── */ .glass-card { background: rgba(255, 255, 255, 0.08); backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px); border: 1px solid rgba(255,255,255,.15); border-radius: 16px; } /* ── filter: efectos de imagen ───────────────── */ .img-project { filter: grayscale(100%); /* blanco y negro */ transition: filter .4s; } .img-project:hover { filter: grayscale(0%) saturate(130%); /* full color al hover */ } /* ── mask-image: desenmascarar ───────────────── */ .fade-bottom { mask-image: linear-gradient(to bottom, black 60%, transparent 100%); -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent); } /* ── text-stroke: texto con borde ────────────── */ .outline-text { -webkit-text-stroke: 1px var(--accent); color: transparent; } /* ── aspect-ratio: proporciones perfectas ────── */ .project-thumb { aspect-ratio: 16 / 9; } .avatar { aspect-ratio: 1; border-radius: 50%; } .card-tall { aspect-ratio: 3 / 4; } /* ── scroll-snap: scroll cinematográfico ─────── */ .scroll-container { overflow-y: scroll; scroll-snap-type: y mandatory; height: 100vh; } .section { scroll-snap-align: start; height: 100vh; }
Generadores de efectos CSS
- 1En tus tarjetas de proyecto: aplica
filter: grayscale(100%)a las imágenes. En hover, anima de vuelta a color. - 2Crea un efecto glassmorphism en la card de contacto usando
backdrop-filter: blur(). - 3Usa Clippy para crear un clip-path diagonal en tu sección hero.
- 4Aplica
-webkit-text-strokea tu nombre o título principal para crear texto solo con contorno.
Transitions:
suavidad intencional
Una transition es la diferencia entre un cambio abrupto y una transición fluida. Son la forma más simple de añadir vida a una interfaz — y las más usadas en el día a día.
/* ── Sintaxis ─────────────────────────────────── */ /* transition: propiedad duración timing-function delay */ .btn { transition: background .25s ease; /* o múltiples propiedades: */ transition: background .25s ease, transform .3s cubic-bezier(.34,1.56,.64,1); /* o todo a la vez (usa con cuidado, puede ser costoso): */ transition: all .25s ease; } /* ── Timing functions: la personalidad de la animación ── */ transition-timing-function: ease; /* rápido al inicio, lento al final */ transition-timing-function: linear; /* velocidad constante */ transition-timing-function: ease-in; /* lento al inicio */ transition-timing-function: ease-out; /* lento al final (más natural) */ transition-timing-function: ease-in-out; /* lento en ambos extremos */ /* cubic-bezier: control total de la curva */ transition-timing-function: cubic-bezier(.34, 1.56, .64, 1); /* spring/rebote */ transition-timing-function: cubic-bezier(.77, 0, .175, 1); /* exponential */ transition-timing-function: cubic-bezier(.16, 1, .3, 1); /* ease out expo */ /* ── Propiedades animables (y performantes) ───── */ /* Usar solo estas — son renderizadas por la GPU: */ transform: translateX(0) translateY(0) scale(1) rotate(0deg); opacity: 0 → 1; /* Evitar animar (fuerzan reflow, son lentas): */ /* width, height, top, left, margin, padding, font-size */ /* ── Patrones de hover comunes ────────────────── */ .card:hover { transform: translateY(-8px); box-shadow: 0 20px 60px rgba(0,0,0,.3); } .btn:hover { transform: scale(1.04); } .link:hover { transform: translateX(4px); /* desplazamiento lateral */ } /* ── will-change: hint para la GPU ───────────── */ .animated-element { will-change: transform, opacity; /* prepara el elemento para animación */ /* Úsalo solo cuando la animación ya ocurre, no siempre */ }
Ve a cubic-bezier.com para crear curvas de animación personalizadas visualmente. El valor cubic-bezier(.34, 1.56, .64, 1) da un efecto de "spring" muy satisfactorio.
@keyframes:
coreografía CSS
Con @keyframes defines secuencias de animación completas — no solo de A a B, sino de A a B a C a D. Son el equivalente de los fotogramas clave de un motion designer.
Animaciones en vivo
Sintaxis completa
/* ── Definir la animación ─────────────────────── */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } /* Múltiples puntos (%) */ @keyframes morphing { 0% { border-radius: 8px; transform: scale(1); } 50% { border-radius: 50%; transform: scale(1.2); } 100% { border-radius: 8px; transform: scale(1); } } /* ── Aplicar la animación ─────────────────────── */ .hero-title { animation: fadeInUp 1.2s cubic-bezier(.16,1,.3,1) both; /* Propiedades individuales: */ animation-name: fadeInUp; animation-duration: 1.2s; animation-timing-function: ease-out; animation-delay: 0.3s; animation-iteration-count: 1; /* o infinite */ animation-direction: normal; /* o alternate (va y vuelve) */ animation-fill-mode: both; /* aplica desde el inicio y se queda al final */ animation-play-state: running; /* o paused — controlable con JS */ } /* ── Efecto de entrada escalonada ─────────────── */ .nav-item:nth-child(1) { animation-delay: 0.1s; } .nav-item:nth-child(2) { animation-delay: 0.2s; } .nav-item:nth-child(3) { animation-delay: 0.3s; } .nav-item:nth-child(4) { animation-delay: 0.4s; } /* ── Reducir movimiento para accesibilidad ───── */ @media (prefers-reduced-motion: reduce) { .hero-title { animation: none; opacity: 1; } }
Clip-path animado: el efecto "revelar"
/* ── Texto que se revela con clip-path ────────── */ @keyframes textReveal { from { clip-path: inset(0 100% 0 0); /* oculto desde la derecha */ opacity: 0; } to { clip-path: inset(0 0% 0 0); /* completamente visible */ opacity: 1; } } .reveal { animation: textReveal 1s cubic-bezier(.77,0,.175,1) forwards; opacity: 0; /* empieza invisible */ } /* ── Imagen que aparece con clip-path ─────────── */ @keyframes imageReveal { from { clip-path: inset(100% 0 0 0); } /* desde abajo */ to { clip-path: inset(0 0 0 0); } } .project-image { animation: imageReveal 1.2s cubic-bezier(.16,1,.3,1) both; }
- 1Crea el @keyframe
fadeInUpy aplícalo al título principal, subtítulo y botón del hero conanimation-delayescalonado (0.1s, 0.3s, 0.5s). - 2Aplica la animación
textRevealcon clip-path a tu nombre en el hero. Es el efecto más impactante de una primera impresión. - 3Añade el @media
prefers-reduced-motion: reducepara deshabilitar animaciones en usuarios que lo soliciten. - 4Explora Animista y añade una animación diferente a las tarjetas de proyecto.
Scroll animations:
CSS puro 2024
Animaciones vinculadas al scroll — sin JavaScript. La CSS Scroll-Driven Animations API es la novedad más emocionante de CSS en años y ya está disponible en todos los navegadores modernos.
Hasta 2023, cualquier animación basada en scroll requería JavaScript (GSAP, Intersection Observer). Ahora CSS puede hacerlo solo con animation-timeline y animation-range. Soporte: Chrome 115+, Firefox 110+, Safari 18+.
/* ── Barra de progreso de lectura ────────────── */ .progress-bar { position: fixed; top: 0; left: 0; width: 100%; height: 3px; background: var(--accent); transform-origin: left; animation: progress-grow linear; animation-timeline: scroll(); /* vinculada al scroll del documento */ animation-range: entry 0% exit 100%; } @keyframes progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } /* ── Elemento que aparece al entrar al viewport ─ */ .section { view-timeline-name: --section-reveal; } .section-content { animation: fadeInUp 0.8s ease both; animation-timeline: view(); /* vinculada a visibilidad del elemento */ animation-range: entry 0% entry 40%; /* se anima mientras entra */ } /* ── Parallax con scroll ──────────────────────── */ .parallax-bg { animation: parallax-move linear; animation-timeline: scroll(); } @keyframes parallax-move { from { transform: translateY(-100px); } to { transform: translateY(100px); } } /* ── Fallback para Intersection Observer (clásico) ─ */ /* Para navegadores sin soporte a scroll-driven: */ .reveal { opacity: 0; transform: translateY(30px); transition: opacity .8s, transform .8s; } .reveal.visible { opacity: 1; transform: translateY(0); }
// IntersectionObserver: detecta cuándo un elemento entra al viewport // Funciona en TODOS los navegadores. Úsalo como fallback o complemento. const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // Si el elemento está entrando en la vista: if (entry.isIntersecting) { entry.target.classList.add('visible'); // Opcional: dejar de observar una vez que ya se vio observer.unobserve(entry.target); } }); }, { threshold: 0.15, // 15% del elemento debe ser visible para activar rootMargin: '-50px' // margen negativo: activa un poco después }); // Observar todos los elementos con clase .reveal document.querySelectorAll('.reveal').forEach(el => { observer.observe(el); });
- 1Añade la barra de progreso de lectura con
animation-timeline: scroll()al header de tu portfolio. - 2Añade la clase
.reveala cada tarjeta de proyecto y sección conopacity: 0; transform: translateY(30px). - 3Crea el
IntersectionObserverenscript.jspara añadir la clase.visiblecuando entren al viewport. - 4Intenta reemplazar el JS por
animation-timeline: view()en Chrome y observa la diferencia.
Portfolio responsive
con animaciones
Integra todo el módulo: Grid, Flexbox, responsive, tipografía fluida, efectos CSS, transitions y animaciones. Tu portfolio completo, vivo, en producción.
Una web portfolio de una página completamente responsive (móvil → tablet → desktop), con sistema tipográfico y de color propio, efectos visuales CSS creativos y animaciones de entrada y scroll. Publicada en Vercel o GitHub Pages.
Checklist técnico de entrega
| Área | Requisito | Puntos |
|---|---|---|
| Layout | Grid para estructura macro, Flex para componentes | 15 |
| Responsive | Mobile-first, mínimo 2 breakpoints, sin overflow horizontal | 20 |
| Tipografía | 2 fuentes pares, escala, clamp() en títulos, 65ch en párrafos | 15 |
| Color | Sistema CSS variables, gradientes, dark mode | 10 |
| Efectos CSS | clip-path, backdrop-filter o filter en elementos clave | 10 |
| Transitions | Hover states en cards, links y botones con cubic-bezier | 10 |
| Animaciones | Entrada hero con @keyframes, scroll reveal en secciones | 15 |
| Accesibilidad | prefers-reduced-motion, alt en imágenes, contraste adecuado | 5 |
Estructura de archivos recomendada
mi-portfolio/ ├── index.html ├── styles/ │ ├── reset.css ← normalize y * {} │ ├── tokens.css ← :root con variables │ ├── layout.css ← Grid y Flex estructura │ ├── components.css ← cards, nav, footer │ ├── typography.css ← fuentes y escala │ └── animations.css ← @keyframes y transitions ├── js/ │ └── scroll-reveal.js ← IntersectionObserver ├── assets/ │ ├── images/ │ └── fonts/ ← si usas fuentes locales └── README.md
Ve a vercel.com → New Project → importa tu repositorio de GitHub. Vercel lo despliega automáticamente. Cada git push actualiza el sitio en producción en segundos.
Inspiración para el proyecto final
✓ Módulo 02 completado
Al finalizar este módulo puedes hacer desde cero:
- Crear cualquier layout con Flexbox y CSS Grid
- Diseñar mobile-first con media queries y unidades fluidas
- Configurar un sistema tipográfico con clamp() y escala
- Usar gradientes, clip-path y efectos CSS avanzados
- Crear transitions y @keyframes expresivas con cubic-bezier
- Implementar scroll animations con CSS y JavaScript
- Publicar en Vercel con deploy automático
→ Módulo 03: Interactividad & JavaScript
DOM manipulation · Eventos · requestAnimationFrame · GSAP · p5.js · Tu diseño cobra vida