Cómo crear plantillas Django conformes con WCAG
El proyecto WebAIM Million analiza cada año las páginas de inicio de los un millón de sitios más populares. En 2021, encontraron un promedio de 51,4 errores de accesibilidad por página. Eso es por página de inicio, no por sitio.
Los desarrolladores de Django tienen una ventaja. El framework fomenta la estructura. Las plantillas viven en un solo lugar. Los formularios manejan la validación. La interfaz de administración se genera a partir de los modelos. Esa estructura facilita la implementación de la accesibilidad y hace que sea más difícil romperla.
Pero Django no escribe plantillas accesibles por ti. Tienes que hacerlo tú.
Empieza con HTML semántico, no con divs
Los lectores de pantalla dependen de un HTML que les indique lo que significan las cosas. Un <button> es un botón. Un elemento <nav> contiene la navegación. Los encabezados desde <h1> hasta <h6> crean un esquema de tu contenido.
Las guías de HTML de Wagtail, que se aplican a cualquier proyecto Django (utilice Wagtail o no), establecen dos principios básicos: escribir HTML válido y escribir HTML semántico. Apuntan al doctype HTML5.
Esto es lo que significa el HTML semántico en la práctica. En lugar de esto:
html
<div class="header"> <div class="logo">...</div> <div class="nav"> <div class="nav-item">Inicio</div> <div class="nav-item">Acerca de</div> </div> </div>
Escribes esto:
html
<header> <div class="logo">...</div> <nav aria-label="Principal"> <ul> <li><a href="/">Inicio</a></li> <li><a href="/about/">Acerca de</a></li> </ul> </nav> </header>
La diferencia no es visual. Es estructural. Una persona usuaria de lector de pantalla puede saltar directamente a la navegación. Sabe cuántos elementos hay en la lista. Escucha "lista, dos elementos" antes de que leas los enlaces.
El propio sitio de documentación de Django hizo estas mejoras. Envolvieron su tabla de contenidos en <nav aria-label="Tabla de contenidos de la documentación">. Hicieron lo mismo con los enlaces anterior/siguiente al pie de las páginas. Pequeños cambios, gran impacto para las personas que usan tecnología de asistencia.
Los campos de formulario necesitan etiquetas, siempre
El sistema de formularios de Django facilita la renderización de campos. {{ form.as_p }} y {{ form.as_table }} generan etiquetas automáticamente. Eso es bueno.
Pero si renderizas los formularios manualmente, tienes que incluir etiquetas. Cada input necesita una. No marcadores de posición. Los marcadores de posición desaparecen cuando el usuario escribe. No son un sustituto.
El reciente proyecto de atajos de teclado del administrador de Django, django-admin-keyshortcuts, tuvo que considerar cuidadosamente las interacciones con los formularios. El equipo añadió atajos como / para enfocar la barra de búsqueda y Ctrl+s para guardar objetos. Esos atajos solo funcionan si los campos del formulario están correctamente etiquetados y pueden recibir el foco.
Aquí tienes un patrón accesible para un campo de formulario en Django:
html
<div class="field-wrapper"> {{ form.email.label_tag }} {{ form.email.errors }} {{ form.email }} {% if form.email.help_text %} <p class="help" id="{{ form.email.auto_id }}_helptext">{{ form.email.help_text }}</p> {% endif %} </div>
El método label_tag genera el elemento <label> correcto con el atributo for apuntando al ID del input. Eso es la base. Sin él, los usuarios de lectores de pantalla no saben qué escribir.
Los desplegables necesitan opciones vacías claras
Un tique de Django de octubre de 2024 (#35870) abordó algo específico: las opciones vacías en los menús desplegables (select). Marijke Luttekes registró el tique, y James Scholes, que es ciego y experto en accesibilidad, proporcionó comentarios.
El problema era qué debería decir la opción vacía. Cuando un desplegable no tiene un valor inicial, Django muestra una opción vacía. Pero, ¿qué texto debería tener esa opción?
James Scholes recomendó "(seleccione una opción)". Los paréntesis son importantes. Interrumpen lo menos posible la navegación por teclado con la primera letra. Si alguien está escribiendo para saltar entre opciones, los paréntesis no interfieren como podría hacerlo otra puntuación.
El tique sigue abierto, pero la lección es clara. Los pequeños detalles importan. El texto dentro de una opción afecta a cómo navegan los usuarios de lectores de pantalla. El comportamiento predeterminado de Django puede no ser óptimo, y es posible que tengas que personalizarlo.
Si estás construyendo formularios con menús desplegables, comprueba qué dice tu opción vacía. Considera si es clara para alguien que aún no puede ver las otras opciones.
La navegación por teclado no es opcional
Algunos usuarios no pueden usar un ratón. Navegan por las interfaces con el tabulador. Usan atajos de teclado. Tus plantillas deben soportar eso.
El equipo de Wagtail CMS ha estado trabajando en comprobaciones de accesibilidad integradas en el propio CMS. Están usando Axe, el mismo motor que potencia muchas herramientas de prueba de accesibilidad, para señalar problemas mientras los editores crean contenido. Una de las cosas que comprueban es el foco del teclado: ¿puedes alcanzar todos los elementos interactivos?
A. Rafey Khan trabajó durante el verano de 2025 en atajos de teclado para el administrador de Django a través de Google Summer of Code. Su paquete, django-admin-keyshortcuts, añade:
/para enfocar la búsquedaj/kpara enfocar el objeto siguiente o anteriorCtrl+spara guardarAlt+dpara confirmar eliminación
Los atajos vienen con un diálogo para que los usuarios puedan descubrirlos. Eso es crucial. Añadir atajos que nadie conoce no sirve de ayuda.
Pero Khan también encontró limitaciones. Algunos atajos no funcionan en Safari. Las teclas modificadoras se comportan de manera diferente según el navegador. Es posible que el equipo tenga que esperar correcciones en la librería subyacente de «hotkeys». La compensación es que el soporte de teclado multinavegador es más difícil de lo que parece.
Si estás construyendo plantillas Django personalizadas, pruébalas solo con teclado. Desconecta el ratón. Navega con el tabulador por cada enlace, botón y campo de formulario. ¿Puedes llegar a todo? ¿Sabes dónde estás? Si no es así, tus plantillas necesitan trabajo.
ARIA: úsalo con moderación o no lo uses
Los atributos WAI-ARIA pueden resolver problemas de accesibilidad, pero también pueden crearlos. Las guías HTML de Wagtail hacen referencia a las «ARIA Authoring Practices» y señalan específicamente: "No ARIA es mejor que una ARIA defectuosa".
Esto viene del propio W3C. Añadir ARIA incorrectamente puede sobrescribir la semántica nativa y empeorar las cosas para los usuarios de lectores de pantalla.
Si tu botón es un <button>, no necesitas role="button". Eso ya está ahí. Si tu navegación es un <nav>, no necesitas role="navigation". El HTML nativo gana.
Usa ARIA cuando estés construyendo algo que HTML no puede expresar. Un panel de pestañas. Un diálogo modal. Una región viva que se actualiza sin recargar la página. Esos casos necesitan ARIA. Para todo lo demás, usa el elemento HTML correcto.
El sitio de documentación de Django añadió etiquetas ARIA a sus regiones de navegación, como aria-label="Tabla de contenidos de la documentación". Eso es apropiado porque desambigua múltiples elementos nav. Sin ello, los usuarios de lectores de pantalla escucharían "navegación, navegación" y no sabrían cuál es cuál.
Prueba con herramientas reales, no solo con esperanza
No puedes adivinar si tus plantillas son accesibles. Tienes que probar.
El equipo de Wagtail está integrando comprobaciones de accesibilidad directamente en el CMS. Están usando Axe y almacenando resultados a lo largo del tiempo para mostrar tendencias. El objetivo es dar a los editores una puntuación y ayudarles a mejorar el contenido a medida que lo crean.
Para los desarrolladores de Django, existen varias herramientas:
- WAVE de WebAIM. Extensiones de navegador gratuitas que muestran los errores visualmente.
- Axe de Deque. Se integra con las herramientas de desarrollo del navegador y puede ejecutarse en integración continua (CI).
- Curlylint y djhtml. Estas herramientas analizan las plantillas Django específicamente para problemas de HTML. Wagtail las usa.
- NVDA en Windows o VoiceOver en Mac. Lectores de pantalla gratuitos. Úsalos.
El proyecto AccChecky, construido en una hackathon, usaba la API de WAVE para comprobar sitios y mostrar resultados con gráficos. Ese es un enfoque. El enfoque más simple es ejecutar WAVE en tus páginas y corregir lo que encuentre.
Un ejemplo: construyendo una navegación accesible
Recorramos una plantilla Django real para un menú de navegación principal.
Primero, la plantilla base podría incluir un bloque para la navegación:
html
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}Mi sitio{% endblock %}</title> </head> <body> <a href="#main" class="skip-link">Saltar al contenido principal</a> <header> <nav aria-label="Principal"> <ul> <li><a href="/" {% if request.path == '/' %}aria-current="page"{% endif %}>Inicio</a></li> <li><a href="/about/" {% if request.path == '/about/' %}aria-current="page"{% endif %}>Acerca de</a></li> <li><a href="/services/" {% if request.path == '/services/' %}aria-current="page"{% endif %}>Servicios</a></li> <li><a href="/contact/" {% if request.path == '/contact/' %}aria-current="page"{% endif %}>Contacto</a></li> </ul> </nav> </header> <main id="main"> {% block content %}{% endblock %} </main> </body> </html>
Esto hace varias cosas:
lang="es"indica al lector de pantalla en qué idioma pronunciar.- El enlace de salto («skip link») permite a los usuarios de teclado omitir la navegación.
<nav aria-label="Principal">identifica la región de navegación.aria-current="page"indica al usuario del lector de pantalla qué página es la actual.<main id="main">proporciona el destino del enlace de salto.
Todo es HTML. Sin magia de ARIA. Simplemente usando los elementos correctamente.
El atajo de la superposición (overlay) y por qué evitarlo
Hay un paquete de PyPI llamado django-all-in-one-accessibility. Instala un widget que añade una barra de herramientas de accesibilidad a tu sitio. Los usuarios pueden cambiar el contraste, aumentar el tamaño del texto y usar un lector de pantalla.
Se instala en dos minutos. No cuesta nada. Parece una solución rápida.
No es una solución.
Las superposiciones tienen problemas fundamentales. Añaden JavaScript que modifica la página después de que se carga. Pueden entrar en conflicto con la propia tecnología de asistencia del usuario. Dan la ilusión de accesibilidad sin corregir el código subyacente. Las guías de Wagtail sobre "No ARIA es mejor que una ARIA defectuosa" se aplican doblemente a las superposiciones.
Si usas una superposición y llamas accesible a tu sitio, te estás engañando a ti mismo y a tus usuarios. La superposición no corrige la falta de texto alternativo en las imágenes. No corrige la estructura de encabezados. No hace que tus formularios tengan etiquetas adecuadas. Solo añade una barra de herramientas.
Construye plantillas accesibles en su lugar. Es más trabajo. También es el único enfoque que realmente funciona.
Lo que Django está haciendo internamente
El propio proyecto Django ha estado trabajando en la accesibilidad. El paquete de atajos de teclado surgió del GSoC 2025 y podría terminar integrándose en el núcleo («core»). El tique sobre las opciones vacías en los menús desplegables está abierto y en discusión. El sitio de documentación se ha actualizado con un mejor HTML semántico.
La propia interfaz de administración de Django, que miles de desarrolladores usan a diario, está recibiendo atención. Los atajos de teclado la hacen utilizable para personas que no pueden usar un ratón. Un mejor etiquetado de formularios ayuda a todo el mundo.
Si estás construyendo plantillas Django, puedes seguir la misma trayectoria. Empieza con HTML semántico. Etiqueta tus formularios. Prueba con teclado y lector de pantalla. Corrige lo que esté roto.
Las herramientas que realmente necesitas
No necesitas herramientas empresariales costosas para crear plantillas Django accesibles. Necesitas:
- Un editor de código
- Un navegador
- La extensión WAVE
- Un lector de pantalla para pruebas
- Curlylint o djhtml para el análisis estático («linting»)
Las guías de interfaz de usuario de Wagtail recomiendan djhtml para formatear plantillas Django y Curlylint para analizarlas. También recomiendan ejecutar make lint para comprobar tu código.
Curlylint comprueba cosas como la falta de texto alternativo en imágenes, el orden incorrecto de los encabezados y la ausencia de etiquetas en los formularios. Se ejecuta sobre tus plantillas, no sobre el HTML renderizado, por lo que detectas problemas temprano.
Añádelo a tu flujo de integración continua (CI). Ejecútalo en cada solicitud de cambios («pull request»). Deja de fusionar código que no supere las comprobaciones básicas de accesibilidad.
La disyuntiva: tiempo frente a demandas judiciales
Construir plantillas accesibles lleva tiempo. Tienes que aprender las reglas. Tienes que probar. Tienes que corregir cosas que se ven bien visualmente pero fallan para los usuarios de lectores de pantalla.
La alternativa es ser demandado.
La ADA (Ley de Estadounidenses con Discapacidades) no tiene un estándar técnico para sitios web, pero los tribunales recurren a las WCAG. WCAG 2.1 Nivel AA es el punto de referencia de facto. Si tu sitio no lo cumple, estás expuesto.
Para los desarrolladores de Django, la elección es clara. Invierte tiempo ahora para construirlo bien. O gasta dinero más tarde en abogados y acuerdos extrajudiciales.
Conclusión
Las plantillas Django son solo HTML con algunas etiquetas de plantilla. HTML tiene la accesibilidad incorporada. Úsala.
Escribe HTML semántico. Usa <nav>, <main>, <header>, <footer>. Etiqueta tus formularios. Asegúrate de que los usuarios de teclado puedan alcanzar todo. Añade enlaces de salto («skip links»). Prueba con tecnología de asistencia real.
La comunidad de Django está trabajando en esto. El administrador está recibiendo atajos de teclado. La documentación está mejorando. Se están discutiendo tiques sobre menús desplegables y opciones vacías.
Puedes esperar a que Django resuelva todos estos problemas por ti. O puedes resolverlos tú mismo en tus plantillas ahora mismo. Un enfoque te deja vulnerable. El otro hace que tu sitio funcione para más personas.

Comments (0)
No comments yet.