Reglas concisas para construir IU accesibles, rápidas y agradables. Use DEBE/DEBERÍA/NUNCA para guiar las decisiones.
Interacciones
Teclado
- DEBE: Soporte completo de teclado según WAI-ARIA APG
- DEBE: Anillos de enfoque visibles y sin obstrucciones (
:focus-visible; agrupar con:focus-within); los elementos fijos/pegajosos nunca cubren el enfoque - DEBE: Gestionar el enfoque (atrapar, mover, devolver) según los patrones APG
- NUNCA:
outline: nonesin un reemplazo de enfoque visible
Objetivos y Entrada
- DEBE: Objetivo de clic ≥24px (móvil ≥44px); si el visual es <24px, expanda el área de clic
- DEBE: Tamaño de fuente de
<input>en móvil ≥16px para evitar el zoom de iOS - NUNCA: Deshabilitar el zoom del navegador (
user-scalable=no,maximum-scale=1) - DEBE:
touch-action: manipulationpara evitar el zoom de doble toque - DEBERÍA: Establecer
-webkit-tap-highlight-colorpara que coincida con el diseño
Formularios
- DEBE: Entradas seguras para hidratación (sin pérdida de enfoque/valor)
- NUNCA: Bloquear pegar en
<input>/<textarea> - DEBE: Los botones de carga muestran un spinner y mantienen la etiqueta original
- DEBE: Enter envía el input enfocado; en
<textarea>, ⌘/Ctrl+Enter envía - DEBE: Mantener el botón de envío habilitado hasta que comience la solicitud; luego deshabilitar con spinner
- DEBE: Aceptar texto libre, validar después—no bloquear la escritura
- DEBE: Permitir el envío de formularios incompletos para mostrar validación
- DEBE: Errores en línea junto a los campos; al enviar, enfocar el primer error
- DEBE:
autocomplete+namesignificativo;typeeinputmodecorrectos - DEBERÍA: Deshabilitar la revisión ortográfica para correos electrónicos/códigos/nombres de usuario
- DEBERÍA: Los marcadores de posición terminan con
…y muestran un patrón de ejemplo - DEBE: Advertir sobre cambios no guardados antes de la navegación
- DEBE: Compatible con gestores de contraseñas y 2FA; permitir pegar códigos
- DEBE: Recortar valores para manejar espacios finales de expansión de texto
- DEBE: Sin zonas muertas en casillas de verificación/botones de opción; etiqueta+control comparten un único objetivo de clic
Estado y Navegación
- DEBE: La URL refleja el estado (enlaces profundos a filtros/pestañas/paginación/paneles expandidos)
- DEBE: Atrás/Adelante restaura la posición de desplazamiento
- DEBE: Los enlaces usan
<a>/<Link>para navegación (soporte para Cmd/Ctrl/clic medio) - NUNCA: Usar
<div onClick>para navegación
Retroalimentación
- DEBERÍA: IU optimista; reconciliar en la respuesta; en caso de fallo, revertir u ofrecer Deshacer
- DEBE: Confirmar acciones destructivas o proporcionar una ventana de Deshacer
- DEBE: Usar
aria-livecortés para notificaciones/validación en línea - DEBERÍA: Puntos suspensivos (
…) para opciones que abren seguimientos ("Renombrar…") y estados de carga ("Cargando…")
Tocar y Arrastrar
- DEBE: Objetivos generosos, affordances claras; evitar interacciones delicadas
- DEBE: Retrasar el primer tooltip; los tooltips posteriores entre pares son instantáneos
- DEBE:
overscroll-behavior: containen modales/paneles deslizantes - DEBERÍA: Al suprimir el rebote de la página (rubber-band), establecer
overscroll-behavior: noneen<html>dentro de@media (pointer: fine); mantener los valores predeterminados de página para punteros gruesos (pull-to-refresh). Probar dispositivos táctiles híbridos:pointerdescribe la entrada principal, ynonetambién deshabilita el encadenamiento de desplazamiento y la navegación nativa por deslizamiento - DEBE: Durante el arrastre, deshabilitar la selección de texto y establecer
inerten los elementos arrastrados - DEBE: Los gestos de arrastre/deslizamiento/pellizco/trayectoria tienen una alternativa de toque/clic y teclado a menos que sea esencial
- DEBE: Si parece cliqueable, debe ser cliqueable
Autofoco
- DEBERÍA: Autofoco en escritorio con una sola entrada primaria; raramente en móvil
Animación
- DEBE: Honrar
prefers-reduced-motion(proporcionar una variante reducida o deshabilitar) - DEBERÍA: Preferir CSS > API de Web Animations > bibliotecas JS
- DEBE: Animar solo propiedades amigables con el compositor (
transform,opacity) - NUNCA: Animar propiedades de diseño (
top,left,width,height) - NUNCA:
transition: all—enumerar propiedades explícitamente - DEBERÍA: Animar solo para aclarar causa/efecto o agregar deleite deliberado
- DEBERÍA: Elegir la curva de aceleración que coincida con el cambio (tamaño/distancia/desencadenante)
- DEBE: Animaciones interrumpibles e impulsadas por entrada; reproducción automática solo para bucles sin sonido y no esenciales
- DEBE: El movimiento de reproducción automática >5s junto a otro contenido tiene controles de pausa, detener u ocultar
- DEBE:
transform-origincorrecto (el movimiento comienza donde "físicamente" debería) - DEBE: Transformaciones SVG en envoltorio
<g>contransform-box: fill-box
Diseño
- DEBERÍA: Alineación óptica; ajustar ±1px cuando la percepción supera a la geometría
- DEBE: Alineación deliberada a la cuadrícula/línea base/bordes—sin colocación accidental
- DEBERÍA: Equilibrar bloqueos de icono/texto (peso/tamaño/espaciado/color)
- DEBE: Verificar en móvil, portátil, ultraancho (simular ultraancho al 50% de zoom)
- DEBE: Respetar las áreas seguras (
env(safe-area-inset-*)) - DEBE: Evitar barras de desplazamiento no deseadas; corregir desbordamientos
- DEBERÍA: Flex/grid sobre medición JS para diseño
Contenido y Accesibilidad
- DEBERÍA: Ayuda en línea primero; tooltips como último recurso
- DEBE: Los esqueletos reflejan el contenido final para evitar cambios de diseño
- DEBE:
<title>coincide con el contexto actual - DEBE: Sin callejones sin salida; siempre ofrecer el siguiente paso/recuperación
- DEBE: Diseñar estados vacíos/dispersos/densos/de error
- DEBERÍA: Comillas rizadas (“ ”); evitar viudas/huérfanas (
text-wrap: balance) - DEBE:
font-variant-numeric: tabular-numspara comparaciones numéricas - DEBE: Señales de estado redundantes (no solo color); los iconos tienen etiquetas de texto
- DEBE: Los nombres accesibles existen incluso cuando los elementos visuales omiten etiquetas
- DEBE: Usar el carácter
…(no...) - DEBE:
scroll-margin-topen encabezados; enlace "Saltar al contenido";<h1>–<h6>jerárquicos - DEBE: Resiliente al contenido generado por el usuario (corto/medio/muy largo)
- DEBE: Fechas/horas/números sensibles a la configuración regional (
Intl.DateTimeFormat,Intl.NumberFormat) - DEBERÍA:
translate="no"en nombres de marca, tokens de código e identificadores para evitar una traducción automática incorrecta - DEBE:
aria-labelpreciso; elementos decorativosaria-hidden - DEBE: Los botones de solo icono tienen
aria-labeldescriptivo - DEBE: Preferir semántica nativa (
button,a,label,table) antes que ARIA - DEBE: Los medios tienen subtítulos/transcripciones/descripciones según corresponda; los controles son operables con teclado; medios decorativos ocultos para la tecnología de asistencia
- DEBE: Espacios de no ruptura:
10 MB,⌘ K, nombres de marca
Manejo de Contenido
- DEBE: Los contenedores de texto manejan contenido largo (
truncate,line-clamp-*,break-words) - DEBE: Los hijos de Flex necesitan
min-w-0para permitir el truncamiento - DEBE: Manejar estados vacíos—sin IU rota para cadenas/arrays vacíos
Rendimiento
- DEBERÍA: Probar en modo de bajo consumo de iOS y Safari en macOS
- DEBE: Medir de manera confiable (deshabilitar extensiones que sesguen el tiempo de ejecución)
- DEBE: Rastrear y minimizar repintados (React DevTools/React Scan)
- DEBE: Perfilar con limitación de CPU/red
- DEBE: Agrupar lecturas/escrituras de diseño; evitar reflujos/repintados
- DEBE: Las mutaciones (
POST/PATCH/DELETE) deben tener un objetivo <500ms - DEBERÍA: Preferir entradas no controladas; entradas controladas deben ser económicas por pulsación de tecla
- DEBE: Virtualizar listas grandes (>50 elementos)
- DEBE: Precargar imágenes sobre el pliegue; carga diferida del resto
- DEBE: Prevenir CLS (dimensiones de imagen explícitas)
- DEBERÍA:
<link rel="preconnect">para dominios CDN - DEBERÍA: Fuentes críticas:
<link rel="preload" as="font">confont-display: swap - DEBERÍA:
<video autoplay muted loop playsinline>sobre GIF animado; proporcionar alternativa estática/de movimiento reducido - DEBERÍA: Los bucles cortos no esenciales incluyen una fuente
<picture>Safari H.264 MP4, una condición de mediosprefers-reduced-motiony un fallback estático
Modo Oscuro y Temas
- DEBE:
color-scheme: darken<html>para temas oscuros - DEBERÍA:
<meta name="theme-color">coincide con el fondo de la página - DEBE:
<select>nativo:background-colorycolorexplícitos (corrección para Windows)
Hidratación
- DEBE: Las entradas con
valuenecesitanonChange(o usardefaultValue) - DEBERÍA: Proteger la representación de fecha/hora contra discrepancias de hidratación
Diseño
- DEBERÍA: Sombras en capas (ambiental + directa)
- DEBERÍA: Bordes nítidos mediante bordes semitransparentes + sombras
- DEBERÍA: Radios anidados: hijo ≤ padre; concéntricos
- DEBERÍA: Consistencia de matiz: teñir bordes/sombras/texto hacia el matiz de fondo
- DEBE: Gráficos accesibles (paletas aptas para daltonismo)
- DEBE: Cumplir con el contraste—preferir APCA sobre WCAG 2
- DEBE: Aumentar el contraste en
:hover/:active/:focus - DEBERÍA: Hacer coincidir la UI del navegador con el fondo
- DEBERÍA: Evitar bandas de degradado de color oscuro (usar imágenes de fondo cuando sea necesario)