Cuándo un SVG es decorativo
El criterio para decidir si un gráfico aporta información, cómo ocultarlo correctamente, la diferencia entre las cuatro formas de ocultar, y el fallo de anunciar dos veces lo mismo.
La mayoría de los SVG de una interfaz no deben anunciarse. Un icono junto a un texto que dice lo mismo, un adorno de fondo, una línea divisoria: anunciarlos es ruido que hace la navegación más lenta y más confusa. Decidir cuáles ocultar tiene un criterio de una sola pregunta, y ocultarlos bien tiene una respuesta que no es la que la gente usa por intuición.
- Aplicar el criterio de una pregunta para decidir si un SVG es decorativo.
- Ocultar un SVG correctamente y saber por qué esa forma y no otra.
- Distinguir las cuatro maneras de ocultar y sus efectos distintos.
- Detectar y corregir la duplicación de anuncios.
La pregunta
Si borraras el SVG y en su lugar no hubiera nada, ¿perdería el usuario información?
Si la respuesta es no, es decorativo. Y la respuesta es no mucho más a menudo de lo que parece:
- Un icono de sobre junto al texto «Enviar mensaje»: decorativo. El texto ya lo dice.
- El mismo icono solo, en un botón sin texto: no decorativo, pero el nombre va en el botón.
- Una ilustración de fondo en una sección: decorativa.
- Un gráfico de barras con datos: no decorativo, y hace falta bastante más que un nombre.
- Una flecha en un enlace «Ver más»: decorativa.
- Un icono de estado en una fila de tabla, sin texto: no decorativo, es el único portador del dato.
- El logotipo en la cabecera, dentro de un enlace a la portada: no decorativo, es el nombre del enlace.
- El mismo logotipo repetido en el pie: decorativo, si ya está anunciado arriba.
El caso del icono de estado merece un comentario porque es el que más se falla. Una tabla donde una columna muestra un tic verde o una cruz roja sin texto: quien usa un lector de pantalla no percibe el color ni la forma. Ese icono tiene que llevar nombre, o mejor, tiene que ir acompañado de texto oculto visualmente.
Cómo ocultarlo
La forma correcta:
<svg aria-hidden="true" viewBox="0 0 24 24" width="20" height="20">
<path d="..." />
</svg>
aria-hidden="true" elimina el elemento y todo su subárbol del árbol de accesibilidad, sin afectar a la presentación visual. Es exactamente lo que se necesita.
Y ahora las cuatro maneras de ocultar algo, que no son intercambiables:
| Mecanismo | Visible | En el árbol de accesibilidad | Enfocable |
|---|---|---|---|
aria-hidden="true" |
Sí | No | Sí, y eso es un problema |
display: none |
No | No | No |
visibility: hidden |
No | No | No |
| Clase de ocultación visual | No | Sí | Sí |
Dos filas merecen explicación.
La primera fila tiene una trampa: aria-hidden no impide el foco. Si dentro del SVG oculto hay algo enfocable, el usuario del teclado llegará a un elemento que existe para el foco y no existe para el lector de pantalla. Eso es una violación directa de las pautas y produce un foco que «desaparece». En SVG decorativo no suele haber nada enfocable, pero si el SVG está dentro de un enlace o un botón, asegúrate de que el propio SVG no tiene tabindex.
La última fila es la técnica opuesta y también necesaria: el texto oculto visualmente pero presente para el lector de pantalla.
.solo-lector {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
Esa combinación exacta es la que funciona: reduce el elemento a un píxel, lo recorta y evita que el texto largo provoque scroll. Las variantes con display: none o visibility: hidden no sirven, porque también lo ocultan al lector.
Con ella, el icono de estado de una tabla se resuelve así:
<td>
<svg aria-hidden="true" width="16" height="16"><use href="#i-check" /></svg>
<span class="solo-lector">Completado</span>
</td>
El icono se oculta y el texto lo sustituye. Es más robusto que poner un aria-label en el SVG porque el texto se traduce como contenido y porque no depende del mapeo de accesibilidad de SVG.
Un botón con icono y texto donde alguien ha puesto nombre al icono «por si acaso»:
<button>
<svg role="img" aria-label="Guardar" width="16" height="16"><use href="#i-disco" /></svg>
Guardar
</button>Un lector de pantalla anuncia: «Guardar Guardar, botón». El nombre accesible del botón se calcula concatenando el contenido, y el contenido incluye el nombre del SVG más el texto.
La variante peor, y muy común en bibliotecas de componentes:
<button aria-label="Guardar cambios">
<svg role="img" aria-label="Icono de guardar" width="16" height="16">...</svg>
Guardar
</button>Aquí el aria-label del botón gana y anuncia «Guardar cambios, botón», ignorando todo lo de dentro. El texto visible dice «Guardar» y el lector dice «Guardar cambios». Es una discrepancia entre el texto visible y el nombre accesible, y es un fallo de conformidad concreto: la pauta de etiqueta en el nombre exige que el nombre accesible contenga el texto visible, para que quien usa control por voz pueda decir «pulsa Guardar» y funcione. Con el nombre siendo «Guardar cambios», el comando por voz «Guardar» puede no encontrar el botón.
Las dos reglas que lo evitan:
Uno: en un elemento con texto visible, el icono va siempre con aria-hidden="true". Sin excepciones y sin «por si acaso».
Dos: si pones aria-label en un control con texto visible, el texto visible tiene que estar contenido en el nombre. «Guardar cambios» contiene «Guardar»: correcto. «Confirmar» no contiene «Guardar»: incorrecto.
Este fallo es el que más aparece en las auditorías reales de sistemas de diseño, y es el más barato de arreglar: es un atributo de más en un componente que se usa en trescientos sitios.
Los SVG que se anuncian solos sin que lo sepas
Tres sitios donde aparece contenido accesible sin que nadie lo haya puesto a propósito.
El title de un sprite. Si el símbolo lleva title, cada instancia lo hereda. Un botón con texto y un icono cuyo símbolo tiene title anuncia doble aunque el use no diga nada. Es la razón, otra vez, de no poner title en los símbolos.
El texto dentro de un SVG decorativo. Una ilustración de fondo que incluye un text con una palabra suelta. Sin aria-hidden, ese texto se anuncia sin contexto. Es especialmente frecuente con ilustraciones exportadas de una herramienta de diseño, donde las capas conservan sus nombres como texto.
El SVG dentro de un img con alt vacío. Ese caso está bien: <img src="adorno.svg" alt=""> es decorativo y correcto. El error es olvidar el alt, porque entonces el lector anuncia el nombre del fichero.
Recorre tu interfaz con un lector de pantalla y cuenta cuántos anuncios duplicados encuentras en botones con icono y texto. Después mira el componente de botón de tu sistema de diseño: si el icono no lleva aria-hidden por defecto, ahí tienes el origen de todos ellos. Arreglarlo en el componente arregla los trescientos usos a la vez.