A un visitante se le corta internet mientras carga tu formulario. Una extensión de Chrome rompe tu JavaScript. Un navegador antiguo no admite el JavaScript que usas. Su lector de pantalla no puede recorrer tu formulario porque las etiquetas están ocultas con CSS.
Los formularios son rutas críticas. Los usuarios necesitan enviarlos. El formulario no puede simplemente romperse. La mejora progresiva es el principio de crear formularios que funcionen en todas partes y añadir después mejoras para los navegadores que puedan aprovecharlas.
Este artículo explica cómo crear formularios que se degraden con elegancia, funcionen sin JavaScript y sigan siendo accesibles para todos.
¿Qué es la mejora progresiva?
La mejora progresiva consiste en empezar con un formulario básico que funcione en los navegadores más antiguos y sin JavaScript, y añadir mejoras encima para los navegadores modernos. La capa 1 (HTML) ofrece un formulario básico con campos, etiquetas y un botón de envío que no necesita JavaScript y funciona en todas partes. La capa 2 (CSS) da estilo al formulario con colores, espacios y diseño, de modo que el formulario sigue funcionando si el CSS no se carga, aunque se vea mal. La capa 3 (JavaScript) añade validación en tiempo real, animaciones fluidas y envío por AJAX, de modo que el formulario sigue funcionando si falla JavaScript y simplemente se envía de la forma tradicional. Si falla cualquier capa, el usuario sigue teniendo un formulario que funciona. Eso es resistencia.
La base: HTML que funciona
Empieza con HTML semántico, con etiquetas, fieldsets y elementos legend bien usados. Un formulario base se parece a <form action="/submit" method="POST"> <label for="email">Email</label> <input type="email" id="email" name="email" required> <label for="message">Message</label> <textarea id="message" name="message" required></textarea> <button type="submit">Send</button> </form>. Este formulario funciona sin JavaScript, sin CSS, en navegadores antiguos, con lectores de pantalla y con navegación por teclado. Esta es tu base. No quites nunca elementos del DOM para sustituirlos por elementos generados con JavaScript, porque si el JavaScript falla, el formulario se rompe. Conserva el HTML semántico.
Degradación elegante con CSS
Añade las mejoras de CSS encima del HTML. Dale al formulario un buen estilo. Pero si el CSS falla, el formulario sigue funcionando.
No ocultes las etiquetas con CSS para apoyarte en los marcadores de posición, porque algunos CSS no se cargan y los lectores de pantalla necesitan las etiquetas en el HTML. No uses CSS para ocultar los indicadores de campo obligatorio, porque si tu "estrella de obligatorio" personalizada no se carga, los usuarios no pueden saber qué campos son obligatorios. Usa mejor el atributo required de HTML. Evita ocultar la etiqueta visualmente y mostrar en su lugar un marcador de posición con label { display: none; } y input::placeholder { content: 'Email'; }. En su lugar, conserva la etiqueta en el HTML y dale el estilo que quieras con label { font-weight: bold; color: #333; }.
Mejoras de JavaScript que se degradan bien
Añade mejoras de JavaScript, pero solo si el formulario ya funciona. Usa la detección de funciones para comprobar si el navegador admite lo que necesitas con if (window._blocked_) { // Use _blocked_ for AJAX submission } else { // Form submits traditionally }. No des por hecho que las funciones existen. Da por hecho que quizá no. Detecta primero.
Validación en tiempo real con alternativa
Usa la validación de HTML como base con <input type="email" required>, para que el navegador valide al enviar. Después añade una validación con JavaScript que se ejecute en tiempo real con input.addEventListener('blur', () => { if (!isValid(input.value)) { input.classList.add('invalid'); showError(input, 'Invalid email'); } });. Muestra los errores mientras el usuario escribe y, si JavaScript falla, la validación integrada del navegador sigue funcionando. El usuario se beneficia de la respuesta en tiempo real y, si JavaScript falla, recibe la respuesta del navegador al enviar. En cualquier caso, la validación se hace.
Envío por AJAX con alternativa tradicional
Crea un formulario tradicional que se envíe al servidor, intercepta después el envío y usa AJAX en su lugar con form.addEventListener('submit', async (e) => { e.preventDefault(); const response = await _blocked_('/submit', { method: 'POST', body: new FormData(form) }); if (response.ok) { showMessage('Success'); } });. Si JavaScript falla, preventDefault nunca se ejecuta, el formulario se envía de la forma tradicional y el usuario ve una recarga de página en lugar de una experiencia fluida. Pero el formulario funciona.
La accesibilidad como mejora progresiva
La accesibilidad no es una función extra. Es la base. Crea formularios accesibles.
Las etiquetas deben vincularse a los campos con los atributos for e id. No con atributos data ni con aria-labels que pueden pasarse por alto. Etiquetas de verdad.
<label for="email">Email</label>
<input id="email">
Usa elementos HTML semánticos (fieldset, legend, button, input). No divs con aspecto de botón.
La navegación por teclado debe funcionar. Tab para recorrer todos los campos. Mayús+Tab para volver atrás. Intro para enviar. Espacio para marcar casillas. Esto funciona por defecto con HTML semántico. No lo rompas con JavaScript.
Cuando lo básico funcione, añade etiquetas ARIA para los lectores de pantalla. Añade indicadores de foco para quienes usan el teclado. Pero son mejoras sobre un HTML ya accesible.
Pruebas de resistencia
Prueba tu formulario con JavaScript desactivado. Desactiva JavaScript en tu navegador e intenta enviarlo. Si el formulario se rompe, no es resistente.
Prueba con redes lentas. Limita tu conexión a 2G. Si el formulario tarda una eternidad en cargarse, los visitantes con internet inestable se irán.
Prueba con navegadores antiguos. Usa una herramienta de pruebas en varios navegadores para comprobar IE 11 (si todavía lo necesitas). Mira qué funciones no se admiten.
Prueba con lectores de pantalla. Usa uno para Windows o para Mac. Escucha cómo anuncia el formulario. Si no tiene sentido para un lector de pantalla, arréglalo.
Prueba solo con el teclado. No uses el ratón. ¿Puedes recorrer el formulario? ¿Puedes enviarlo?
Detección de funciones, no de navegadores
No compruebes navegadores concretos. Comprueba funciones, en lugar de usar una detección de navegador como if (navigator.userAgent.includes('Chrome')) { /* use _blocked_ */ }. Usa mejor la detección de funciones, como if (window._blocked_) { /* use _blocked_ */ }. La detección de funciones es más fiable, porque una actualización del navegador que añada compatibilidad con _blocked_ funcionará con tu código, pero la detección de navegador no.
Cómo crea WEMASY formularios resistentes
Los formularios de WEMASY se crean con principios de mejora progresiva: funcionan sin JavaScript, tienen etiquetas y HTML semántico, y las mejoras de JavaScript son opcionales, de modo que los navegadores antiguos reciben un formulario que funciona y los modernos disfrutan de interacciones fluidas.
Consulta las funciones de resistencia en tu plan de WEMASY.