Principios de diseño para ingenieros de software
Fundamentos de diseño para ingenieros de software: tipografía, color, espaciado, animación, patrones de interfaces de IA, tokens de diseño y 48 casos prácticos de productos actuales.
Actualizado el 18 de mayo de 2026
Actualización del 18 de mayo de 2026: Se renovó el índice de Estudios de diseño para alinearlo con el corpus actual de 48 estudios y se ampliaron los Patrones de interfaz de IA con evidencia de flujos de trabajo agénticos: puntos de control, estados de aprobación, confianza en las fuentes y verificación visible.
Actualización de mayo de 2026: Se agregó una nota sobre el borrador de trabajo de marzo de 2026 de WCAG 3.0 y la postura del W3C de que WCAG 2.2 y 3.0 coexistirán. WCAG 2.2 sigue siendo el estándar al que debes apuntar para el trabajo actual de accesibilidad.
Actualización de febrero de 2026: Se agregaron dos secciones nuevas: Patrones de interacción (8 paradigmas a partir del estudio de Framer, Flighty, Halide, Warp, Bear, Craft y Superhuman) y Patrones de interfaz de IA (diseño centrado en citas, fases de streaming, transparencia de errores de Perplexity). Se actualizaron los Patrones web a 2026 con posicionamiento de anclas, animaciones impulsadas por scroll y @starting-style. Se actualizó la accesibilidad para reflejar la estandarización ISO de WCAG 2.2. Consulta Estudios de diseño para ver análisis detallados de 48 productos excepcionales.
He pasado años estudiando diseño mientras desarrollaba software, absorbiendo principios de leyendas como Dieter Rams y analizando a fondo interfaces de productos como Linear, Stripe y Raycast. Esta guía condensa ese entendimiento en la referencia completa que me habría gustado tener cuando empecé a preocuparme por cómo se veía y se sentía mi software.
El diseño no es decoración. Es comunicación. Cada píxel comunica función, jerarquía y significado. La diferencia entre el software que se siente de aficionado y el software que se siente profesional está en entender estos principios y aplicarlos de forma consistente.
Esta guía parte de que ya sabes escribir código. Te enseña a ver: a entender por qué algunas interfaces se sienten fluidas mientras otras se sienten caóticas y, más importante aún, cómo construir las primeras.
Tabla de contenidos
Parte 1: Fundamentos
- Psicología Gestalt
- Tipografía
- Teoría del color
- Jerarquía visual
- Espaciado y ritmo
- Principios de animación
Parte 2: Interacción e IA
Parte 3: Filosofía de diseño
Parte 4: Implementación
Parte 5: Referencia
Psicología Gestalt
“El todo es distinto de la suma de sus partes.” — Kurt Koffka
La psicología Gestalt, desarrollada en la Alemania de los años 1920, explica cómo los seres humanos perciben la información visual. El cerebro no ve píxeles individuales, sino que organiza los elementos en patrones con significado. Domina estos principios para controlar cómo los usuarios perciben tus interfaces.
Proximidad
Los elementos cercanos entre sí se perciben como un grupo.
Este es el principio Gestalt más poderoso en el diseño de UI. El espacio comunica relación más que cualquier otra propiedad visual.
INCORRECTO (espaciado uniforme = sin agrupación):
┌─────────────────┐
│ Label │
│ │
│ Input Field │
│ │
│ Label │
│ │
│ Input Field │
└─────────────────┘
CORRECTO (espaciado desigual = grupos claros):
┌─────────────────┐
│ Label │
│ Input Field │ ← Ajustado (4px) - relacionados
│ │
│ │ ← Amplio (24px) - separando grupos
│ Label │
│ Input Field │ ← Ajustado (4px) - relacionados
└─────────────────┘
Implementación en CSS:
.form-group {
margin-bottom: 24px; /* Between groups: wide */
}
.form-group label {
margin-bottom: 4px; /* Label to input: tight */
display: block;
}
Implementación en SwiftUI:
VStack(alignment: .leading, spacing: 4) { // Tight within group
Text("Email")
.font(.caption)
.foregroundStyle(.secondary)
TextField("you@example.com", text: $email)
.textFieldStyle(.roundedBorder)
}
.padding(.bottom, 24) // Wide between groups
Similitud
Los elementos que comparten características visuales parecen estar relacionados.
Cuando los elementos se ven iguales, los usuarios asumen que funcionan igual. Por eso los sistemas de diseño usan estilos de botón, tratamientos de tarjetas y tipografía consistentes.
Ejemplo de navegación:
┌───────────────────────────────────┐
│ [Dashboard] [Projects] [Settings] │ ← Mismo estilo = misma función
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Card │ │Card │ │Card │ │ ← Mismo estilo = mismo tipo de contenido
│ └─────┘ └─────┘ └─────┘ │
│ │
│ [+ New Project] │ ← Estilo diferente = función diferente
└───────────────────────────────────┘
Figura-fondo
El contenido debe separarse claramente del fondo.
El cerebro necesita distinguir la “figura” (en qué enfocarse) del “fondo” (el trasfondo). Una mala relación figura-fondo genera confusión visual.
Técnicas: - Contraste (figura clara sobre fondo oscuro, o viceversa) - Sombras (elevar la figura sobre el fondo) - Bordes (delimitar los contornos de la figura) - Desenfoque (desenfocar el fondo, enfocar la figura)
/* Strong figure-ground relationship */
.card {
background: var(--color-surface); /* Figure */
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); /* Elevation */
}
.modal-overlay {
background: rgba(0, 0, 0, 0.5); /* Dim ground */
backdrop-filter: blur(4px); /* Blur ground */
}
Región común
Los elementos dentro de un límite se perciben como agrupados.
Encerrar elementos dentro de un contenedor visual (tarjeta, caja, área con bordes) indica que pertenecen al mismo grupo.
Continuidad
El ojo sigue trayectorias, líneas y curvas.
Usa la alineación y el flujo visual para guiar la atención a través de tu interfaz.
CONTINUIDAD EN LA ALINEACIÓN:
┌────────────────────────────────┐
│ Logo [Nav] [Nav] [Nav] │ ← Alineados en el eje horizontal
├────────────────────────────────┤
│ │
│ Headline │
│ ───────────────────────────── │ ← El ojo sigue el borde izquierdo
│ Paragraph text continues │
│ along the same left edge │
│ │
│ [Primary Action] │ ← Sigue en el borde izquierdo
└────────────────────────────────┘
Cierre
El cerebro completa las formas incompletas.
Los usuarios no necesitan que cada píxel esté dibujado: completan mentalmente las formas conocidas. Esto permite diseños más minimalistas y elegantes.
/* Horizontal scroll with partial card (closure) */
.card-carousel {
display: flex;
gap: 16px;
overflow-x: auto;
padding-right: 48px; /* Show partial card = scroll hint */
}
.card-carousel .card {
flex: 0 0 280px; /* Fixed width, partial visible */
}
Referencia rápida de Gestalt
| Principio | Regla | Uso principal |
|---|---|---|
| Proximidad | Relacionado = cerca, no relacionado = lejos | Campos de formulario, secciones de contenido |
| Similitud | Misma apariencia = misma función | Botones, tarjetas, navegación |
| Figura-fondo | Separación clara de capas | Tarjetas, modales, overlays |
| Región común | Los límites agrupan contenido | Secciones de configuración, tarjetas de usuario |
| Continuidad | Seguir líneas y alineación | Líneas de tiempo, flujo de lectura |
| Cierre | El cerebro completa las formas | Íconos, indicadores de scroll, esqueletos |
Tipografía
“La tipografía es el oficio de dotar al lenguaje humano de una forma visual duradera.” — Robert Bringhurst
La tipografía es la base del diseño de interfaces. El texto comunica funcionalidad, jerarquía y marca. Una tipografía deficiente hace que las interfaces sean más difíciles de usar; una gran tipografía es invisible: simplemente funciona.
Escala tipográfica
Una escala consistente crea armonía visual. Usa una proporción matemática.
La escala 1.25 (recomendada para UI):
:root {
/* Base: 16px (1rem) */
--text-xs: 0.64rem; /* 10.24px - use sparingly */
--text-sm: 0.8rem; /* 12.8px - captions, labels */
--text-base: 1rem; /* 16px - body text */
--text-lg: 1.25rem; /* 20px - lead text */
--text-xl: 1.563rem; /* 25px - h4 */
--text-2xl: 1.953rem; /* 31.25px - h3 */
--text-3xl: 2.441rem; /* 39px - h2 */
--text-4xl: 3.052rem; /* 48.8px - h1 */
}
Altura de línea (interlineado)
La altura de línea afecta drásticamente la legibilidad. Distintos tipos de contenido requieren diferente interlineado.
| Tipo de contenido | Altura de línea | ¿Por qué? |
|---|---|---|
| Encabezados | 1.1 - 1.2 | Ajustado, en negrita, corto |
| Texto de UI | 1.3 - 1.4 | Etiquetas, botones |
| Texto del cuerpo | 1.5 - 1.7 | Párrafos legibles |
| Texto extenso | 1.7 - 2.0 | Artículos, documentación |
Longitud de línea (medida)
La longitud de línea óptima previene la fatiga visual y mejora la comprensión lectora.
- Óptimo: 45-75 caracteres por línea
- Objetivo: 50-65 caracteres
- Máximo absoluto: 85 caracteres
p {
max-width: 65ch; /* ch unit = width of '0' character */
}
.article-body {
max-width: 70ch;
margin: 0 auto;
}
Selección de fuentes
Fuentes del sistema primero. Se cargan al instante, coinciden con la plataforma y están optimizadas para pantallas.
:root {
--font-sans: system-ui, -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
--font-mono: ui-monospace, 'SF Mono', 'Cascadia Code',
'JetBrains Mono', Consolas, monospace;
}
Usa fuentes personalizadas para: - Diferenciación de marca (sitios de marketing) - Sensación editorial o de publicación - Intención de diseño específica no alcanzable con fuentes del sistema
Peso de fuente para jerarquía
Usa el peso para establecer jerarquía, no solo el tamaño.
h1 { font-weight: 700; } /* Bold */
h2 { font-weight: 600; } /* Semibold */
h3 { font-weight: 600; } /* Semibold */
.lead { font-weight: 500; } /* Medium */
p { font-weight: 400; } /* Regular */
.meta { font-weight: 400; color: var(--text-muted); }
Referencia rápida de tipografía
| Propiedad | Texto del cuerpo | Encabezados | Etiquetas de UI |
|---|---|---|---|
| Tamaño | 16-18px | 24-48px | 12-14px |
| Peso | 400 | 600-700 | 500 |
| Altura de línea | 1.5-1.7 | 1.1-1.2 | 1.3-1.4 |
| Longitud de línea | 45-75ch | N/A | N/A |
| Alineación | Izquierda | Centrado OK | Izquierda |
Teoría del color
“El color es un poder que influye directamente en el alma.” — Wassily Kandinsky
El color comunica más rápido que las palabras. Establece el estado de ánimo, guía la atención, señala significado y construye reconocimiento de marca.
La regla 60-30-10
La distribución de color más confiable para interfaces equilibradas.
┌──────────────────────────────────────────┐
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ 60% - Dominant (Background)
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░│ 30% - Secondary (Cards, sections)
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░│
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓██████▓▓▓▓▓▓▓▓▓▓░░░░░░░░│ 10% - Accent (Buttons, links)
└──────────────────────────────────────────┘
Crear una paleta de colores
Cada interfaz necesita estos colores semánticos:
:root {
/* Brand */
--color-primary: hsl(220, 80%, 50%);
--color-primary-hover: hsl(220, 80%, 45%);
/* Semantic */
--color-success: hsl(142, 76%, 36%); /* Green - positive */
--color-warning: hsl(38, 92%, 50%); /* Amber - caution */
--color-error: hsl(0, 84%, 60%); /* Red - danger */
/* Neutrals */
--color-background: hsl(0, 0%, 100%);
--color-surface: hsl(220, 14%, 96%);
--color-border: hsl(220, 13%, 91%);
/* Text */
--color-text: hsl(220, 13%, 13%);
--color-text-secondary: hsl(220, 9%, 46%);
--color-text-muted: hsl(220, 9%, 64%);
}
Psicología del color
| Color | Psicología | Uso en UI |
|---|---|---|
| Azul | Confianza, estabilidad, calma | Finanzas, tecnología, corporativo |
| Verde | Crecimiento, naturaleza, éxito | Salud, ecología, estados positivos |
| Rojo | Energía, urgencia, peligro | Alertas, ventas, errores |
| Naranja | Calidez, entusiasmo | CTAs, marcas lúdicas |
| Amarillo | Optimismo, precaución | Advertencias, destacados |
| Morado | Lujo, creatividad | Productos premium |
| ### Diseño con prioridad en modo oscuro (Vercel) | ||
| Vercel diseña primero para modo oscuro y luego deriva el modo claro. Esto produce mejores interfaces oscuras porque el modo oscuro se convierte en la consideración principal, no en algo agregado al final. |
/* Design dark first, derive light */
:root {
/* Dark mode defaults */
--color-background: hsl(0, 0%, 0%);
--color-surface: hsl(0, 0%, 7%);
--color-border: hsl(0, 0%, 15%);
--color-text: hsl(0, 0%, 93%);
--color-text-secondary: hsl(0, 0%, 63%);
}
@media (prefers-color-scheme: light) {
:root {
--color-background: hsl(0, 0%, 100%);
--color-surface: hsl(0, 0%, 97%);
--color-border: hsl(0, 0%, 89%);
--color-text: hsl(0, 0%, 9%);
--color-text-secondary: hsl(0, 0%, 40%);
}
}
Cuándo usarlo: Herramientas para desarrolladores, apps de contenido multimedia, paneles de control: contextos donde los usuarios pasan sesiones largas y el modo oscuro reduce la fatiga visual.
Contraste de accesibilidad
| Nivel | Texto normal | Texto grande | Componentes de UI |
|---|---|---|---|
| AA | 4.5:1 | 3:1 | 3:1 |
| AAA | 7:1 | 4.5:1 | N/A |
| WCAG 2.2 se convirtió en un estándar ISO (ISO/IEC 40500:2025) en octubre de 2025, con criterios añadidos para visibilidad del foco, entrada redundante y autenticación accesible. Adiciones clave: los indicadores de foco no deben quedar completamente ocultos por otro contenido (2.4.11), y la autenticación no debe depender únicamente de pruebas de función cognitiva (3.3.8). El W3C publicó una versión actualizada de WCAG 2.2 en diciembre de 2024, que se espera que se publique como ISO/IEC 40500:2026 a finales de 2026. |
WCAG 3.0 sigue siendo un borrador de trabajo. La revisión más reciente se publicó en marzo de 2026 y no reemplaza a WCAG 2.2; el W3C afirma que ambos estándares coexistirán. El Accessibility Guidelines Working Group planea publicar una cronología proyectada de WCAG 3 en 2026, pero WCAG 2.2 sigue siendo el estándar al que debes apuntar para el trabajo actual.
Herramientas: WebAIM Contrast Checker, selector de color de Chrome DevTools
Jerarquía visual
“El diseño es el embajador silencioso de tu marca.” — Paul Rand
La jerarquía visual controla qué ven los usuarios primero, segundo y tercero. Sin una jerarquía clara, los usuarios tienen que esforzarse para encontrar información. Con ella, las interfaces se sienten fluidas.
Las seis herramientas de la jerarquía
1. Tamaño — Los elementos más grandes atraen la atención primero
.hero-title { font-size: 3rem; } /* Dominant */
.section-title { font-size: 1.5rem; } /* Secondary */
.body-text { font-size: 1rem; } /* Baseline */
2. Peso — La negrita se adelanta, el peso ligero retrocede
h1 { font-weight: 700; }
.lead { font-weight: 500; }
p { font-weight: 400; }
3. Color y contraste — Alto contraste = atención
.title { color: var(--color-text); } /* Near black */
.meta { color: var(--color-text-muted); } /* Gray */
4. Posición — Las posiciones clave importan
F-PATTERN (content pages): Z-PATTERN (landing pages):
████████████████████████ 1 ──────────────────► 2
████████ ↘
████ ↘
██ ↘
3 ──────────────────► 4
5. Espacio en blanco — El aislamiento crea importancia
.hero { padding: 120px 48px; } /* Generous space */
.data-table { padding: 12px; } /* Dense content */
6. Profundidad y elevación — Los elementos que se proyectan al frente exigen atención
:root {
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1);
}
.card { box-shadow: var(--shadow-sm); }
.card:hover { box-shadow: var(--shadow-md); }
.modal { box-shadow: var(--shadow-lg); }
Patrones aplicados
Presencia colaborativa (Figma): Varios cursores de usuarios con etiquetas de nombre, resaltados de selección y contornos de componentes crean un documento vivo. El color de cada colaborador es distinto, pero tiene el mismo peso visual: ningún cursor es “más llamativo” que otro.
Indicadores de estado sutiles (Vercel): El estado de despliegue usa indicadores sutiles y persistentes en lugar de alertas intrusivas. Una barra delgada de color en la parte superior comunica el estado (compilando, desplegado, fallido) sin interrumpir el flujo de trabajo.
Analogías de diseño del mundo real (Flighty): Las visualizaciones del progreso de vuelo reflejan instrumentos físicos de aviación: curvas de altitud, indicadores de velocidad y mapas de puertas de embarque usan metáforas visuales familiares en lugar de barras de progreso abstractas.
La prueba de entrecerrar los ojos
Entrecierra los ojos al mirar tu diseño. ¿Todavía puedes ver la jerarquía? Si la respuesta es sí, es sólida.
Espaciado y ritmo
“El espacio en blanco es como el aire: es necesario para que el diseño respire.” — Wojciech Zieliński
El espaciado es la estructura invisible del diseño. Un espaciado consistente crea ritmo visual: la sensación de que los elementos pertenecen a un sistema coherente.
La cuadrícula de 8px
La cuadrícula de 8px es el estándar de la industria porque: - Se divide de manera uniforme (8, 16, 24, 32, 40, 48…) - Funciona con densidades de pantalla comunes (1x, 1.5x, 2x, 3x) - Crea un ritmo consistente sin hacer cálculos
:root {
--space-1: 4px; /* Tight: icon gaps */
--space-2: 8px; /* Compact: inline elements */
--space-3: 12px; /* Snug: form fields */
--space-4: 16px; /* Default: most gaps */
--space-6: 24px; /* Spacious: card padding */
--space-8: 32px; /* Section gaps */
--space-12: 48px; /* Major sections */
--space-16: 64px; /* Page sections */
--space-20: 80px; /* Hero spacing */
}
Espaciado interno vs externo
Interno (padding): Espacio dentro de un elemento Externo (margin): Espacio entre elementos
Regla: El espaciado interno normalmente debe ser mayor que el espaciado externo dentro de grupos relacionados.
.card {
padding: 24px; /* Internal: spacious */
margin-bottom: 16px; /* External: less than padding */
}
Patrones de espaciado de componentes
Tarjetas:
.card { padding: 24px; border-radius: 12px; }
.card-header { margin-bottom: 16px; }
.card-title { margin-bottom: 4px; } /* Tight to subtitle */
Botones:
.btn { padding: 12px 24px; border-radius: 8px; }
.btn--sm { padding: 8px 16px; }
.btn--lg { padding: 16px 32px; }
.btn-group { display: flex; gap: 12px; }
Formularios:
.form-row { margin-bottom: 24px; }
.form-label { margin-bottom: 4px; }
.form-help { margin-top: 4px; }
.form-actions { margin-top: 32px; display: flex; gap: 12px; }
Referencia rápida de espaciado
| Contexto | Espaciado recomendado |
|---|---|
| Del ícono al texto | 4-8px |
| De etiqueta a campo | 4px |
| Entre grupos de formulario | 24px |
| Relleno de tarjeta | 20-24px |
| Separación entre tarjetas | 16-24px |
| Relleno de sección (móvil) | 48-64px |
| Relleno de sección (desktop) | 80-96px |
| Relleno de botón (h/v) | 24px / 12px |
| — |
Principios de animación
“La animación no es el arte de dibujos que se mueven, sino el arte de movimientos que se dibujan.” — Norman McLaren
La animación da vida a las interfaces. Bien ejecutada, guía la atención, comunica estados y genera conexión emocional. Mal ejecutada, frustra y distrae.
El principio fundamental
La animación debe sentirse inevitable, no decorativa.
Buena animación: 1. Comunica algo que el diseño estático no puede 2. Reduce la carga cognitiva al mostrar relaciones 3. Se siente natural y esperada 4. Desaparece de la percepción consciente
Mala animación: 1. Existe solo porque “se ve bien” 2. Ralentiza al usuario 3. Llama la atención sobre sí misma 4. Genera ansiedad o impaciencia
Principios clave para UI
1. Anticipación — Prepara a los usuarios para lo que viene.
.button {
transition: transform 0.1s ease-out;
}
.button:active {
transform: scale(0.97); /* Slight press before action */
}
2. Seguimiento — Deja que el movimiento se complete de forma natural con un asentamiento tipo resorte.
.panel {
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) {
isOpen = true
}
3. Ease-In, Ease-Out — Nada en la naturaleza se mueve a velocidad constante.
| Curva | Cuándo usar | Carácter |
|---|---|---|
ease-out |
Elementos que entran | Inicio rápido, parada suave |
ease-in |
Elementos que salen | Inicio suave, salida rápida |
ease-in-out |
Cambios de estado | Fluido en todo momento |
linear |
Indicadores de carga | Continuo, mecánico |
4. Puesta en escena — Dirige la atención a lo que importa. Solo un elemento debe moverse a la vez, a menos que estén coreografiados como grupo.
5. Escalonamiento — Los elementos deben llegar en secuencia, no todos a la vez.
.list-item {
animation: fadeSlideIn 0.3s ease-out both;
}
.list-item:nth-child(1) { animation-delay: 0ms; }
.list-item:nth-child(2) { animation-delay: 50ms; }
.list-item:nth-child(3) { animation-delay: 100ms; }
.list-item:nth-child(4) { animation-delay: 150ms; }
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
Guía de tiempos
| Duración | Caso de uso | Sensación |
|---|---|---|
| 50-100ms | Micro-interacciones (hover, presionar) | Respuesta instantánea |
| 150-200ms | Cambios de estado simples (alternar, seleccionar) | Ágil |
| 250-350ms | Transiciones medianas (deslizar panel, voltear tarjeta) | Fluido |
| 400-500ms | Movimientos grandes (transiciones de página, modales) | Deliberado |
Rendimiento: la regla de oro
Solo anima transform y opacity — están acelerados por GPU y no provocan recálculo de layout.
/* BAD: Animating layout */
.panel { transition: left 0.3s, width 0.3s; }
/* GOOD: Using transform */
.panel { transition: transform 0.3s; }
Cuándo NO animar
-
El usuario tiene
prefers-reduced-motionactivadocss @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } -
La animación no aporta información — spinners gratuitos, elementos que rebotan
- Los usuarios tienen prisa — estados de error, validación de formularios, resultados de búsqueda
- La animación retrasaría acciones repetidas — los atajos de teclado deben omitir la animación
- Los datos ya están cargados — Bear usa cero estados de carga al precargar el contenido, haciendo que la app se sienta instantánea. Si puedes precargar, omite el skeleton/spinner por completo.
// Bear's approach: preload so no loading state is needed
struct NoteListView: View {
@Query var notes: [Note] // SwiftData loads from disk instantly
// No loading state, no skeleton, no spinner — data is always there
var body: some View {
List(notes) { note in
NoteRow(note: note)
}
}
}
Referencia rápida de animación
:root {
/* Durations */
--duration-instant: 0.1s;
--duration-fast: 0.15s;
--duration-normal: 0.25s;
--duration-slow: 0.4s;
/* Easings */
--ease-out: cubic-bezier(0.0, 0.0, 0.58, 1.0);
--ease-in: cubic-bezier(0.42, 0.0, 1.0, 1.0);
--ease-in-out: cubic-bezier(0.42, 0.0, 0.58, 1.0);
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
}
Patrones de interacción
“La mejor interfaz es no tener interfaz.” — Golden Krishna
Los patrones de interacción definen cómo los usuarios manipulan, navegan y comprenden tu producto. Estos patrones se extraen del estudio de productos que ofrecen interacciones excepcionales.
Manipulación directa (Framer)
Haz tangibles los conceptos abstractos. Framer transforma los breakpoints de CSS —números abstractos— en controles arrastrables. Los usuarios ven cómo los layouts se adaptan en tiempo real.
/* Breakpoint handle styling */
.breakpoint-handle {
position: absolute;
top: 0;
bottom: 0;
width: 4px;
background: var(--accent);
cursor: col-resize;
opacity: 0.6;
transition: opacity 0.15s ease;
}
.breakpoint-handle:hover,
.breakpoint-handle:active {
opacity: 1;
width: 6px;
}
Cuándo usar: Cualquier configuración donde el resultado sea visual —redimensionar arrastrando, selectores de color, desplazamiento en líneas de tiempo.
Interfaces sensibles al contexto (Flighty, Figma)
Muestra solo lo relevante para el momento actual. Flighty usa 15 estados distintos para el seguimiento de vuelos. El panel de propiedades de Figma se transforma por completo según lo que hayas seleccionado.
| Fase (Flighty) | Lo que ve el usuario |
|---|---|
| 24h antes | Código de confirmación, información de terminal |
| En el aeropuerto | Número de puerta, hora de embarque |
| En vuelo | Tiempo restante, progreso, hora estimada de llegada |
| Aterrizaje | Puertas de conexión, ruta a pie |
enum ContextState: CaseIterable {
case farOut, dayBefore, headToAirport, atAirport
case atGate, boarding, inFlight, landed, connection
static func current(for flight: Flight, context: UserContext) -> ContextState {
// Factor in: time, location, flight status
// Return the single most relevant state
}
}
Anti-patrón: Mostrar todos los controles y atenuar los irrelevantes. Esto genera ruido visual.
Activación inteligente (Halide)
Las herramientas deben detectar el contexto y activarse solas. La lupa de enfoque de Halide aparece al arrastrar el foco y desaparece al soltar. No se necesitan botones de alternancia.
struct IntelligentlyActivated<Content: View>: ViewModifier {
let isInteracting: Bool
@State private var isVisible = false
func body(content: Content) -> some View {
content
.opacity(isVisible ? 1 : 0)
.scaleEffect(isVisible ? 1 : 0.95)
.animation(.easeInOut(duration: 0.2), value: isVisible)
.onChange(of: isInteracting) { _, newValue in
if newValue {
withAnimation { isVisible = true }
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
if !isInteracting { isVisible = false }
}
}
}
}
}
Diseño de modo dual (Halide, Warp)
Los cambios de modo deben transformar la UI, no solo alternar elementos. Los modos Auto y Manual de Halide son interfaces completamente diferentes. Warp conecta CLI y GUI a través de cuatro métodos de entrada (escritura, paleta, IA, ratón) sin forzar a los usuarios a un solo paradigma.
Contenido estructurado (Warp, Bear, Craft)
Añade estructura al contenido tradicionalmente desestructurado. Warp convierte la salida del terminal en bloques discretos que se pueden copiar, compartir o volver a ejecutar. Bear te permite organizar notas en línea mientras escribes (#tag/subtag). Craft permite que cualquier bloque se convierta en página —la estructura emerge del uso, no de una jerarquía predefinida.
Entrenamiento progresivo (Superhuman)
Enseña a los usuarios el camino rápido mediante la exposición repetida. La paleta Cmd+K de Superhuman siempre muestra los atajos de teclado junto a los resultados. Cada uso es una micro-lección.
/* Always show shortcut alongside command name */
.command-result {
display: flex;
justify-content: space-between;
padding: 8px 12px;
}
.command-shortcut {
font-family: var(--font-mono);
font-size: 12px;
color: var(--text-muted);
background: var(--bg-subtle);
padding: 2px 6px;
border-radius: 4px;
}
Anti-patrón: Modales de tutorial que explican funciones. La explicación se olvida; la práctica se recuerda.
Patrones de interfaz de AI
«Las mejores interfaces de AI hacen visible el proceso de la máquina y permiten verificar sus resultados».
Las interfaces de AI enfrentan desafíos únicos: los usuarios no pueden predecir los resultados, verificar su precisión con solo observarlos y, a menudo, tampoco pueden saber si el sistema funciona o está fallando.
El problema central
| Software tradicional | Software de AI |
|---|---|
| El resultado es predecible | El resultado varía |
| Los errores son evidentes | Los errores parecen plausibles |
| Los usuarios verifican mediante pruebas | Los usuarios verifican consultando las fuentes |
| Carga = espera | Carga = trabajo en curso (muéstralo) |
| Confianza de forma predeterminada | La confianza debe ganarse |
Diseño centrado en las citas (Perplexity)
Cada afirmación factual debe incluir un enlace a su fuente. Perplexity incorpora citas en línea [1] en cada afirmación, con vistas previas al pasar el cursor y un panel de fuentes persistente.
.citation-marker {
position: relative;
color: var(--accent);
cursor: pointer;
font-size: 0.8em;
vertical-align: super;
}
.citation-preview {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
width: 280px;
padding: 12px;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
Antipatrón: interfaces de AI que generan afirmaciones sin fuentes rastreables. Si el modelo no puede citar una afirmación, la interfaz debe señalarlo.
Indicadores de las fases de generación (Perplexity)
Muestra a los usuarios qué está haciendo la AI, no solo que está trabajando. Sustituye los indicadores de carga genéricos por indicadores de fase: «Buscando…» → «Leyendo 4 fuentes…» → «Redactando la respuesta…»
.phase-indicator {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
background: color-mix(in srgb, var(--phase-color) 10%, transparent);
border-radius: 16px;
font-size: 13px;
color: var(--phase-color);
transition: all 0.3s ease;
}
.loading-dots span {
width: 4px;
height: 4px;
background: currentColor;
border-radius: 50%;
animation: pulse 1.4s ease-in-out infinite;
}
Transparencia ante los errores
Cuando la AI falle o no tenga certeza, indícalo claramente; no lo ocultes tras un texto que suene convincente.
| Situación | Patrón inadecuado | Patrón adecuado |
|---|---|---|
| Poca confianza | Afirmarlo con seguridad | «No tengo certeza, pero…» con un estilo visual menos destacado |
| No se encontraron fuentes | Inventar texto | «No pude encontrar fuentes para esta afirmación» |
| Fuentes contradictorias | Elegir una sin indicarlo | Mostrar ambas y resaltar el conflicto |
| Información desactualizada | Presentarla como actual | «Al [fecha]…» con un indicador de actualidad |
Idea clave: los usuarios perdonan a una AI que reconoce con honestidad su incertidumbre. No perdonan a una AI que se equivoca con total seguridad.
Evidencia del flujo de trabajo con agentes
Los agentes de AI necesitan estados de interfaz que demuestren el trabajo realizado, no que simplemente narren el esfuerzo. Un buen flujo de trabajo con agentes hace comprensible el progreso mediante puntos de control: plan aceptado, fuentes recopiladas, cambios aplicados, pruebas ejecutadas, revisión pendiente y lanzamiento bloqueado o listo.
| Estado del agente | Patrón de interfaz | Por qué es importante |
|---|---|---|
| Planificación | Objetivo y criterios de aceptación explícitos | Evita que el agente optimice la actividad en lugar del resultado |
| Exploración | Lista de fuentes con nivel de confianza y actualidad | Permite distinguir los hechos verificados de las suposiciones de trabajo |
| Ejecución | Resumen de los archivos modificados vinculado a los puntos de control | Permite revisar los cambios sin leer toda la transcripción |
| Verificación | Evidencia de pruebas, rutas, capturas de pantalla o ejecución | Separa las pruebas reales de una confianza artificial |
| Lanzamiento | Estado de aprobación, implementación o revisión nativa | Evita que la publicación oculte trabajo sin terminar tras verificaciones locales exitosas |
Antipatrón: un único estado de «Listo» para un trabajo de agentes compuesto por varios pasos. El trabajo complejo necesita una cadena de custodia visible: qué cambió, qué lo demostró, qué se rechazó y qué todavía requiere el criterio humano.
Dieter Rams: diez principios
«Menos, pero mejor». — Dieter Rams
Dieter Rams es el diseñador industrial más influyente del siglo XX. Como jefe de diseño de Braun entre 1961 y 1995, creó productos que siguen siendo atemporales décadas después. Su trabajo inspiró directamente el lenguaje de diseño de Apple.
Los diez principios del buen diseño
1. El buen diseño es innovador No copies. Combina los avances tecnológicos con un diseño innovador.
2. El buen diseño hace útil un producto Cada elemento debe cumplir un propósito. La forma sigue a la función.
3. El buen diseño es estético La belleza no es superficial: es esencial. Los productos que usamos a diario influyen en nuestro bienestar.
4. El buen diseño hace comprensible un producto Los usuarios no deberían necesitar instrucciones. La interfaz se explica por sí misma.
5. El buen diseño es discreto El diseño debe complementar, no abrumar. El contenido del usuario es el protagonista, no tu UI.
/* Obtrusive: UI competes with content */
.editor {
background: linear-gradient(135deg, purple, blue);
border: 3px dashed gold;
}
/* Unobtrusive: UI recedes, content shines */
.editor {
background: var(--color-background);
border: 1px solid var(--color-border);
}
6. El buen diseño es honesto No uses patrones oscuros. No prometas más de lo que puedes cumplir. Sé transparente respecto de las limitaciones.
7. El buen diseño es duradero Evita tendencias que envejezcan rápidamente. Prefiere lo clásico a lo pasajero.
TRENDY (will date): TIMELESS:
- Extreme glassmorphism - Clean typography
- Neon colors, glitch effects - Subtle elevation
- Aggressive gradients - Neutral palette with considered accent
8. El buen diseño es minucioso hasta el último detalle Nada debe ser arbitrario. Estados de carga, estados vacíos, estados de error: todo debe estar diseñado.
9. El buen diseño respeta el medioambiente El rendimiento también tiene un impacto ambiental. Respeta la atención del usuario. Escribe código eficiente.
10. El buen diseño es la menor cantidad de diseño posible Elimina todo lo que no sea necesario. El mejor diseño es invisible.
Patrones web de 2026
El CSS nativo ahora reemplaza a JavaScript en un conjunto cada vez mayor de problemas de diseño e interacción. Entre 2025 y 2026 llegaron a los navegadores de producción el posicionamiento mediante anclas, las animaciones controladas por el desplazamiento y @starting-style; a mediados de 2026 se sumaron el ajuste automático del tamaño de los controles de formulario, las decoraciones de espacios y el ajuste automático del texto.
Aquí, el estado de compatibilidad importa más que la novedad. Una función disponible en un solo motor es una mejora progresiva; una función clasificada como Baseline Newly available puede usarse como base con seguridad. La siguiente tabla distingue ambas categorías a agosto de 2026.
| Función | Chrome | Firefox | Safari | Estado |
|---|---|---|---|---|
field-sizing |
123 | 152 | 26.2 | Baseline Newly available |
shape-outside: rect() / xywh() |
149 | 149 | 17.2 | Baseline Newly available |
background-clip: border-area |
150 | — | 18.2 | Dos motores |
Decoraciones de espacios (column-rule en grid/flex) |
149 | — | — | Solo Chrome |
text-fit |
150 | — | — | Solo Chrome |
focusgroup |
150 | — | — | Solo Chrome |
Fuentes: Novedades de la plataforma web en junio y julio, web.dev.
Consultas de contenedor
Define el tamaño de los componentes según su contenedor, no según el viewport.
.card-grid {
container-type: inline-size;
container-name: card-grid;
}
.card {
display: grid;
gap: 16px;
padding: 20px;
}
@container card-grid (min-width: 400px) {
.card {
grid-template-columns: auto 1fr;
}
}
@container card-grid (min-width: 600px) {
.card {
padding: 32px;
gap: 24px;
}
}
El selector :has()
Selección del elemento padre según sus hijos, algo que antes era imposible sin JavaScript.
/* Card with image gets different padding */
.card:has(img) {
padding: 0;
}
.card:has(img) .card-content {
padding: 20px;
}
/* Form group with error */
.form-group:has(.input:invalid) .form-label {
color: var(--color-error);
}
/* Highlight navigation when on that page */
.nav-item:has(a[aria-current="page"]) {
background: var(--color-surface);
}
Anidamiento de CSS
Anidamiento nativo sin preprocesadores.
.card {
background: var(--color-surface);
border-radius: 12px;
padding: 24px;
& .card-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 8px;
}
& .card-body {
color: var(--color-text-secondary);
line-height: 1.6;
}
&:hover {
box-shadow: var(--shadow-md);
}
@media (min-width: 768px) {
padding: 32px;
}
}
Decoraciones de espacios
Los espacios de grid y flex pueden tener sus propias líneas, por lo que los divisores ya no requieren pseudoelementos, bordes en cada elemento hijo ni un contenedor adicional por columna. Solo está disponible en Chrome 149 y versiones posteriores, lo que la convierte en una mejora progresiva y no en una base.
.pricing-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 32px;
/* Vertical rules between columns, horizontal between rows */
column-rule: 1px solid var(--color-border);
row-rule: 1px solid var(--color-border);
}
El enfoque anterior agregaba un border-left a todos los elementos excepto al primero, pero dejaba de funcionar en cuanto el grid pasaba a una segunda fila. Las decoraciones se dibujan en el propio espacio, por lo que la distribución sigue siendo correcta cuando los elementos cambian de fila.
Como solo es compatible con un motor, considera estas líneas meramente decorativas y nunca el recurso que distingue contenidos con significados diferentes. Si un diseño se vuelve ambiguo sin ellas, ese diseño falla en Firefox y Safari.
Controles de formulario que se ajustan a su contenido
field-sizing: content permite que los campos de entrada, las áreas de texto y los selectores crezcan o se reduzcan según lo que escriba el usuario, reemplazando el JavaScript basado en la altura de desplazamiento que se vuelve a implementar en cada base de código.
.comment-box {
field-sizing: content;
min-height: 3lh; /* floor: three lines */
max-height: 12lh; /* ceiling: then scroll */
}
.tag-input {
field-sizing: content;
min-width: 8ch;
}
Combínalo siempre con límites min-/max-. Sin un mínimo, un campo vacío se contrae hasta casi desaparecer; sin un máximo, un texto largo pegado empuja el botón de envío fuera de la pantalla.
Esta función alcanzó el estado Baseline Newly available en junio de 2026, por lo que es segura como mecanismo principal y no solo como mejora.
Texto que se ajusta a su caja
text-fit ajusta el tamaño de la fuente para ocupar el ancho de su contenedor, lo que resuelve los casos de titulares destacados y cifras grandes en paneles que antes necesitaban un script de medición.
.stat-value {
text-fit: consistent; /* one size for the whole box */
}
Solo está disponible en Chrome 150. Define primero un font-size normal para que los demás motores usen un tamaño elegido de forma deliberada en lugar del predeterminado:
.stat-value {
font-size: clamp(2rem, 8vw, 6rem); /* the real answer everywhere */
text-fit: consistent; /* refinement where supported */
}
clamp() ya resuelve la mayoría de los casos para los que se busca esta función y cuenta con compatibilidad universal. Usa text-fit cuando la longitud del contenido varíe tanto que ningún valor de clamp funcione en todos los casos.
Bordes degradados sin trucos
background-clip: border-area pinta un fondo en la caja del borde, lo que permite crear bordes degradados con una regla de dos líneas en lugar de recurrir a elementos anidados o a un truco con mask-composite.
.featured-card {
border: 2px solid transparent;
border-radius: 12px;
background:
linear-gradient(var(--color-surface), var(--color-surface)) padding-box,
linear-gradient(135deg, #6366f1, #ec4899) border-area;
}
Está disponible en Chrome 150 y Safari 18.2; Firefox aún no lo ha implementado. Declara primero un border-color sólido para que la alternativa sea un borde real y no uno transparente.
Navegación con las teclas de flecha sin un controlador de keydown
El atributo focusgroup indica al navegador que un conjunto de controles constituye una sola unidad de teclado: Tab entra al grupo una vez, las teclas de flecha permiten desplazarse dentro de él y Tab sale. Las barras de herramientas, las listas de pestañas, los controles segmentados y los grupos de botones con comportamiento de opciones de radio necesitan esta interacción, que además es uno de los aspectos que más suelen implementar mal los componentes creados manualmente.
<div role="toolbar" focusgroup="wrap">
<button>Bold</button>
<button>Italic</button>
<button>Underline</button>
</div>
wrap hace que, al presionar una flecha en el último elemento, se vuelva al primero. De forma predeterminada, la navegación se detiene en los extremos.
Solo está disponible en Chrome 150, así que conserva el controlador de keydown existente hasta que se amplíe la compatibilidad. Conviene conocer el atributo desde ahora porque define con precisión el comportamiento accesible: una barra de herramientas debe representar una sola parada de tabulación, no cinco, y esa expectativa existe desde décadas antes que el atributo. Las prácticas de creación de ARIA describen el patrón independientemente de cómo se implemente.
Integración con HTMX
Interactividad controlada desde el servidor sin frameworks pesados de JavaScript.
<!-- Load content on click -->
<button hx-get="/api/more-items"
hx-target="#item-list"
hx-swap="beforeend"
hx-indicator="#loading">
Load More
</button>
<!-- Form with inline validation -->
<form hx-post="/api/contact"
hx-target="#form-response"
hx-swap="outerHTML">
<input type="email" name="email"
hx-post="/api/validate-email"
hx-trigger="blur"
hx-target="next .error" />
<span class="error"></span>
</form>
Posicionamiento mediante anclas
Posicionamiento nativo con CSS de un elemento respecto a otro, sin necesidad de JavaScript. Resulta útil para tooltips, popovers y menús desplegables que siguen a los elementos que los activan.
/* Anchor an element to another */
.trigger {
anchor-name: --my-trigger;
}
.tooltip {
position: fixed;
position-anchor: --my-trigger;
top: anchor(bottom);
left: anchor(center);
translate: -50% 8px;
}
Animaciones controladas por el desplazamiento
Vincula el progreso de una animación con la posición de desplazamiento. Permite crear indicadores de progreso de lectura, efectos de paralaje y secuencias de aparición sin JavaScript.
/* Reading progress bar */
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: var(--color-primary);
transform-origin: left;
animation: progress linear;
animation-timeline: scroll();
}
@keyframes progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
@starting-style
Define los estilos iniciales de los elementos que ingresan al DOM, lo que permite crear animaciones de entrada solo con CSS y sin JavaScript.
.card {
opacity: 1;
transform: translateY(0);
transition: opacity 0.3s ease, transform 0.3s ease;
@starting-style {
opacity: 0;
transform: translateY(10px);
}
}
Sistema de tokens de diseño
Un sistema completo de tokens para mantener la coherencia en toda tu aplicación.
:root {
/* Colors */
--color-text: #1a1a1a;
--color-text-secondary: #666666;
--color-text-muted: #999999;
--color-background: #ffffff;
--color-surface: #f8f9fa;
--color-surface-elevated: #ffffff;
--color-border: #e5e7eb;
--color-primary: #3b82f6;
--color-primary-hover: #2563eb;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* Typography */
--font-sans: system-ui, -apple-system, sans-serif;
--font-mono: "SF Mono", Consolas, monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Spacing (8px base) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
/* Borders */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
/* Transitions */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--duration-fast: 100ms;
--duration-normal: 200ms;
}
Modo oscuro bien hecho
No te limites a invertir los colores: rediseña la interfaz para contextos oscuros.
@media (prefers-color-scheme: dark) {
:root {
/* Neutrals */
--color-background: hsl(220, 13%, 10%);
--color-surface: hsl(220, 13%, 15%);
--color-surface-elevated: hsl(220, 13%, 18%);
--color-border: hsl(220, 13%, 23%);
/* Text (inverted) */
--color-text: hsl(220, 9%, 93%);
--color-text-secondary: hsl(220, 9%, 70%);
--color-text-muted: hsl(220, 9%, 55%);
/* Adjust saturation for dark mode */
--color-primary: hsl(220, 80%, 60%);
--color-success: hsl(142, 70%, 45%);
--color-error: hsl(0, 80%, 65%);
/* Shadows in dark mode need adjustment */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}
}
Principios del modo oscuro: - Reduce la saturación en superficies grandes - Aumenta la luminosidad de los colores de acento - Intensifica las sombras (necesitan más contraste) - Diseña el modo oscuro de forma intencional, no como algo secundario
Flujos de extracción de Figma
Transformar archivos de diseño en código de producción requiere extraer de forma sistemática los tokens de diseño: colores, tipografía, espaciado y efectos que definen tu lenguaje de diseño.
Exportación de variables de Figma
La función nativa Variables de Figma ofrece la ruta de extracción más limpia:
Pasos para exportar:
1. Abre el archivo de Figma → panel Local Variables
2. Haz clic en el menú de la colección → “Export to JSON”
3. Guarda el archivo como figma-variables.json
Estructura de tokens de JSON:
{
"colors": {
"primitive": {
"blue-500": { "value": "#3b82f6", "type": "color" },
"blue-600": { "value": "#2563eb", "type": "color" }
},
"semantic": {
"primary": { "value": "{colors.primitive.blue-500}", "type": "color" },
"primary-hover": { "value": "{colors.primitive.blue-600}", "type": "color" }
}
},
"spacing": {
"1": { "value": "4px", "type": "spacing" },
"2": { "value": "8px", "type": "spacing" },
"4": { "value": "16px", "type": "spacing" }
}
}
Transformación de tokens a CSS
Propiedades personalizadas de CSS:
:root {
/* Primitive colors (direct values) */
--color-blue-50: #eff6ff;
--color-blue-100: #dbeafe;
--color-blue-500: #3b82f6;
--color-blue-600: #2563eb;
--color-blue-900: #1e3a8a;
/* Semantic colors (reference primitives) */
--color-primary: var(--color-blue-500);
--color-primary-hover: var(--color-blue-600);
--color-background: var(--color-white);
--color-surface: var(--color-gray-50);
/* Spacing (8px grid) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
/* Typography */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--line-height-tight: 1.25;
--line-height-normal: 1.5;
/* Effects */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
}
Tokens del modo oscuro:
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--color-gray-900);
--color-surface: var(--color-gray-800);
--color-text: var(--color-gray-100);
--color-text-secondary: var(--color-gray-400);
/* Adjusted shadows for dark mode */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}
}
Transformación de tokens a SwiftUI
Extensión de colores:
import SwiftUI
extension Color {
// MARK: - Primitive Colors
static let blue50 = Color(hex: "eff6ff")
static let blue500 = Color(hex: "3b82f6")
static let blue600 = Color(hex: "2563eb")
// MARK: - Semantic Colors
static let brandPrimary = Color.blue500
static let brandPrimaryHover = Color.blue600
// MARK: - Surface Colors
static let surfaceBackground = Color(light: .white, dark: Color(hex: "0f172a"))
static let surfaceElevated = Color(light: Color(hex: "f8fafc"), dark: Color(hex: "1e293b"))
}
extension Color {
init(hex: String) {
// Standard hex parsing implementation
}
init(light: Color, dark: Color) {
self.init(UIColor { traits in
traits.userInterfaceStyle == .dark ? UIColor(dark) : UIColor(light)
})
}
}
Constantes de espaciado:
enum Spacing {
static let xs: CGFloat = 4 // --space-1
static let sm: CGFloat = 8 // --space-2
static let md: CGFloat = 16 // --space-4
static let lg: CGFloat = 24 // --space-6
static let xl: CGFloat = 32 // --space-8
}
// Usage
VStack(spacing: Spacing.md) {
// ...
}
.padding(Spacing.lg)
Lista de verificación para la entrega del diseño
Qué deben exportar los diseñadores:
| Tipo de recurso | Formato | Notas |
|---|---|---|
| Colores | Variables JSON | Incluye los modos claro y oscuro |
| Tipografía | Exportación de estilos | Fuente, tamaño, grosor, interlineado |
| Espaciado | Variables JSON | Unidad base documentada |
| Iconos | SVG | Contornos, un solo color |
| Imágenes | PNG @2x/@3x o WebP | Con compresión |
| Componentes | Enlaces de Figma | Como referencia durante la implementación |
Criterios de control de calidad:
- [ ] Todos los colores están definidos como variables (sin valores hexadecimales codificados directamente)
- [ ] La tipografía utiliza estilos de texto definidos
- [ ] El espaciado sigue el sistema de cuadrícula (base de 8px)
- [ ] Se proporcionan variantes para el modo oscuro
- [ ] Los estados interactivos están documentados (hover, activo, deshabilitado)
- [ ] Los puntos de quiebre responsivos están señalados
- [ ] Los requisitos de accesibilidad están indicados (relaciones de contraste)
El desarrollador recibe:
- Archivos de tokens (JSON/CSS/Swift, según la plataforma)
- Especificaciones de los componentes con medidas
- Recursos exportados en los formatos requeridos
- Documentación de las interacciones (estados, animaciones)
- Anotaciones de accesibilidad
Tablas de referencia rápida
Principios Gestalt
| Principio | Regla | Uso |
|---|---|---|
| Proximidad | Relacionado = cercano | Formularios, secciones |
| Similitud | Misma apariencia = misma función | Botones, tarjetas |
| Figura-fondo | Separación clara entre capas | Modales, tarjetas |
| Continuidad | Seguir líneas | Líneas de tiempo, alineación |
| Cierre | El cerebro completa las formas | Iconos, indicios de desplazamiento |
Tipografía
| Elemento | Tamaño | Grosor | Interlineado |
|---|---|---|---|
| Texto principal | 16px | 400 | 1.5-1.7 |
| Encabezados | 24-48px | 600-700 | 1.1-1.2 |
| Etiquetas de UI | 12-14px | 500 | 1.3-1.4 |
| Pies de imagen | 12px | 400 | 1.4 |
Roles de color
| Rol | Modo claro | Modo oscuro |
|---|---|---|
| Fondo | #ffffff | #0f172a |
| Superficie | #f4f5f7 | #1e293b |
| Borde | #e4e6ea | #334155 |
| Texto | #1a1a2e | #f1f5f9 |
| Texto atenuado | #6b7280 | #94a3b8 |
| Primario | #3b82f6 | #60a5fa |
| Éxito | #22c55e | #4ade80 |
| Error | #ef4444 | #f87171 |
Escala de espaciado
| Token | Valor | Uso |
|---|---|---|
| –space-1 | 4px | Espacios entre iconos |
| –space-2 | 8px | Elementos en línea |
| –space-4 | 16px | Espacios predeterminados |
| –space-6 | 24px | Relleno de tarjetas |
| –space-8 | 32px | Espacios entre secciones |
| –space-16 | 64px | Secciones de página |
Lista de verificación del diseño
Antes de publicar cualquier interfaz, verifica lo siguiente:
Gestalt
- [ ] Los elementos relacionados están más cerca entre sí que los no relacionados (Proximidad)
- [ ] Las funciones similares tienen estilos similares (Similitud)
- [ ] Hay una separación clara entre el primer plano y el fondo (Figura-fondo)
- [ ] La mirada recorre el diseño de forma natural (Continuidad)
Tipografía
- [ ] El tamaño de fuente base es de al menos 16px
- [ ] El interlineado es de 1.5 o más para el texto principal
- [ ] La longitud de línea es inferior a 75 caracteres
- [ ] La jerarquía es clara (se distinguen 3 niveles)
- [ ] Se utiliza una escala coherente en todo el diseño
Color
- [ ] Todo el texto cumple una relación de contraste de 4.5:1 (WCAG AA)
- [ ] El color no es el único indicador (también se usan iconos o etiquetas)
- [ ] El modo oscuro está diseñado de forma intencional
- [ ] Se sigue la distribución 60-30-10
Jerarquía visual
- [ ] Se puede identificar el elemento más importante
- [ ] La mirada sigue el orden previsto
- [ ] Hay un CTA claro por sección
- [ ] La escala tipográfica es coherente
Espaciado
- [ ] Todo el espaciado utiliza la escala definida (sin números arbitrarios)
- [ ] Las tarjetas y los componentes tienen un relleno coherente
- [ ] El espaciado en dispositivos móviles es cómodo
- [ ] La alineación con la cuadrícula es coherente (base de 8px)
Interacción
- [ ] ¿Los usuarios pueden alcanzar sus objetivos sin tener que pensar en la herramienta?
- [ ] ¿La UI se adapta al contexto actual?
- [ ] ¿Las herramientas solo son visibles cuando resultan pertinentes?
- [ ] ¿El uso repetido enseña métodos más rápidos?
Interfaces de AI
- [ ] Cada afirmación factual cuenta con una fuente rastreable
- [ ] La transmisión muestra las fases del proceso, no solo un indicador de carga
- [ ] Los estados de error son transparentes, no están ocultos
- [ ] Los resultados con baja confianza se diferencian visualmente
Comprobación de Dieter Rams
- [ ] ¿Se puede eliminar algo?
- [ ] ¿Cada elemento cumple una función?
- [ ] ¿Se sentiría anticuado dentro de 5 años?
- [ ] ¿He diseñado todos los estados?
Recursos
Libros: - As Little Design as Possible de Sophie Lovell (Dieter Rams) - The Elements of Typographic Style de Robert Bringhurst
Herramientas: - Comprobador de contraste de WebAIM - Generador de escalas tipográficas - Figma Tokens Studio — Gestión de tokens de diseño
Sistemas de diseño: - Apple HIG - Material Design 3 - Radix UI - shadcn/ui
Estudios de diseño
Análisis a fondo de 48 productos excepcionales que documentan patrones y principios dignos de adoptar.
Herramientas para desarrolladores e IA
| Producto | Aporte principal |
|---|---|
| Figma | Presencia multiusuario, paneles adaptados al contexto |
| Warp | Terminal basado en bloques, puente entre CLI y GUI |
| Framer | Diseño adaptable visual, controles de propiedades |
| Vercel | Excelencia en modo oscuro, estado ambiental |
| Linear | Optimistic UI, flujo de trabajo centrado en el teclado |
| Raycast | Sistema de extensiones, acciones rápidas |
| Stripe | Documentación sobresaliente, diseño API |
| Perplexity | IA centrada en las citas, fases de transmisión |
| Obsidian | Componibilidad con enfoque local-first, interfaces de grafos de conocimiento |
Herramientas nativas de Apple y creativas
| Producto | Aporte principal |
|---|---|
| Flighty | 15 estados inteligentes, Live Activities, visualización de datos |
| Halide | Activación inteligente, controles mediante gestos |
| Bear | Tipografía como prioridad, etiquetado integrado |
| Craft | Experiencia nativa primero y multiplataforma, páginas anidadas |
| Things | Fechas aplazadas, patrones de captura rápida |
| Darkroom | UI oscura e inmersiva, edición centrada en la fotografía |
| Procreate | Herramientas creativas centradas en los gestos |
| Overcast | Ingeniería de audio invisible como diseño de interfaces |
| Camo | UI profesional para producción de video |
| Ivory | Cronologías cuidadosamente diseñadas, precisión lúdica |
| Anybox | Transparencia nativa de la plataforma |
| Drafts | Claridad en la captura centrada en el texto |
| Notion Calendar | Precisión del calendario, integración con el espacio de trabajo |
Productividad, conocimiento y finanzas
| Producto | Aporte principal |
|---|---|
| Superhuman | Regla de los 100 ms, aprendizaje de la paleta de comandos, incorporación mediante la práctica |
| Notion | Sistema de bloques, comandos con barra diagonal |
| Arc | Espacios, vista dividida, barra de comandos |
| Todoist | Minimalismo cálido, máxima moderación |
| Amie | Productividad alegre, minimalismo cálido |
| Loom | Profesionalismo cercano en el video asíncrono |
| Pitch | Lenguaje visual audaz para presentaciones |
| Readwise Reader | Herramientas para la lectura profunda, identidad de marca cósmica |
| Copilot Money | Visualización cinematográfica de datos financieros |
| 1Password | Seguridad sin fricciones |
| Mercury | Sofisticación cinematográfica en la banca |
Consumo, interacción social y confianza
| Producto | Aporte principal |
|---|---|
| Spotify | Color, emoción y escala |
| Duolingo | La ludificación como lenguaje de diseño |
| Signal | Seguridad mediante la simplicidad |
| Airbnb | Confianza a escala de mercado |
| Bluesky | Transparencia algorítmica |
| Letterboxd | El cine como objeto social |
| Strava | Los datos de GPS como moneda social |
| Apple Music | Voz editorial, sonido espacial |
| Headspace | La calma como estrategia de interfaz |
| Zomato | UX gastronómica impulsada por la personalidad |
Productos físicos, juegos y accesibilidad
| Producto | Aporte principal |
|---|---|
| Balatro | Ciclos de retroalimentación, sistemas de sensaciones de juego |
| Rivian | Fotografía de aventura y tipografía monumental |
| Teenage Engineering | Las restricciones como identidad estética |
| OKO | Accesibilidad auditiva y háptica |
| CARROT Weather | La personalidad como elemento diferenciador en una aplicación de utilidad |
Esta guía crece con la práctica. Los principios de diseño son atemporales, pero su aplicación evoluciona con la tecnología y el conocimiento.