Cuando el código dice: «Te escucho»
\n\nImagina que pierdes la vista por un día. Tu aplicación de mensajería favorita en Go de repente se queda en silencio. Los botones no se verbalizan, los formularios no se completan y los errores de validación son solo rectángulos rojos. Desagradable, ¿verdad? Y para millones de personas con discapacidad, esto no es un experimento, sino la realidad.
\n\nLa accesibilidad (o a11y — de «a» + 11 letras + «y») no se trata de «marcar una casilla por cumplir». Se trata de que tu servicio Go no apague la luz para el 15% de la población mundial. En este artículo, analizaremos cómo implementar la accesibilidad en proyectos Go sin fanatismo, pero con un beneficio real. ¡Allá vamos!
\n\nPor qué la accesibilidad en Go no es una opción, sino un estándar
\n\nGo es un lenguaje para backend, pero eso no significa que no participe en la creación de una interfaz accesible. Si escribes una API para el frontend, generas HTML en el servidor o creas utilidades CLI, ya estás influyendo en la accesibilidad. La mala noticia: muchos desarrolladores Go piensan que «a11y es cosa de frontend». La buena noticia: puedes solucionarlo en una tarde.
\n\n¿Qué es la accesibilidad web desde el punto de vista de Go?
\n\nLa accesibilidad web (web accessibility) es la capacidad de un sitio o aplicación para ser utilizado por personas con diferentes limitaciones: visión, audición, motricidad, capacidades cognitivas. En el contexto de Go, esto significa:
\n\n- \n
- Un marcado HTML correcto generado por el servidor (por ejemplo, a través de
html/template); \n - Atributos ARIA correctos para contenido dinámico; \n
- Navegación lógica con el teclado; \n
- Mensajes de error claros (no «Error 500», sino «No se pudo guardar el archivo: espacio insuficiente»). \n
Y sí, Go es el lenguaje ideal para esto. Su tipificación estricta y herramientas integradas permiten verificar las plantillas sobre la marcha. Pero vayamos por partes.
\n\nMarcado semántico: el fundamento de la accesibilidad en Go
\n\nCuando generas HTML a través de html/template, eres el arquitecto de la interfaz. Si tu código escupe un <div> para cada botón, los lectores de pantalla (screen readers) no entenderán qué elemento es. Pero si usas <button>, dirán: «Botón. Pulse para enviar el formulario».
Ejemplo: un formulario accesible en Go
\n\nSupongamos que escribes un formulario de registro. Opción mala:
\n\n// Mal: sin semántica\ntmpl := `<div class="form">\n <div>Nombre</div>\n <input type="text" id="name">\n <div class="error">{{.NameError}}</div>\n</div>`\n\n\nOpción buena — con <label> y aria-describedby:
// Bien: marcado semántico + ARIA\ntmpl := `<form>\n <label for="name">Nombre</label>\n <input type="text" id="name" aria-describedby="name-error">\n <span id="name-error" role="alert">{{if .NameError}}{{.NameError}}{{end}}</span>\n</form>`\n\n\n¿Qué cambió? El lector de pantalla ahora sabe: esto es un formulario, el campo de entrada está vinculado a una etiqueta y el error es una alerta. El usuario escuchará: «Nombre. Editar texto. Error: campo obligatorio».
\n\nAtributos ARIA: cuando el HTML no es suficiente
\n\nA veces las etiquetas estándar no son suficientes. Por ejemplo, haces pestañas (tabs) con Go + HTMX. Sin ARIA, sonarán como «enlace, enlace, enlace...». Pero con ARIA, sonarán como «Pestaña 1, seleccionada. Pestaña 2. Pestaña 3».
\n\nCómo agregar ARIA en plantillas Go
\n\nLos atributos ARIA se pasan como atributos normales en HTML. Aquí hay un ejemplo para pestañas:
\n\n<div role="tablist" aria-label="Configuración del perfil">\n <button role="tab" aria-selected="{{if eq .Tab "profile"}}true{{else}}false{{end}}" \n aria-controls="panel-profile" id="tab-profile">Perfil</button>\n <button role="tab" aria-selected="{{if eq .Tab "security"}}true{{else}}false{{end}}" \n aria-controls="panel-security" id="tab-security">Seguridad</button>\n</div>