Descripción extensa de una imagen: accesible con lector de pantalla y visible sin imágenes activas
El objetivo de este artículo es explicar cómo podemos tener una descripción extensa de una imagen en la propia página, de tal manera que:
- sea accesible para los lectores de pantalla
- se visualice cuando la imagen no esté cargada (bien porque tenemos las imágenes desactivadas, bien porque ya no se encuentra disponible, etc.)
Todo ello sin depender del atributo longdesc
, que no siempre es soportado, ni de los típicos enlaces [D] junto a la imagen (conocidos como D-Link); y asegurando que no dé problemas cuando se deshabilita el javascript o las CSS.
Este artículo se me ocurrió después de leer el artículo de Steve Faulkner Detecting if images are disabled in browsers, en el cual explicaba cómo podemos detectar por javascript si las imágenes están deshabilitadas o no se han cargado.
Descargar el ejemplo (RAR, 13Kb)
La descarga y uso del ejemplo es completamente libre, pero os agradecería mucho que compartierais mejoras que se os ocurran o problemas que detectéis.
He probado su funcionamiento con NVDA, Explorer 7, Explorer 8, Explorer 9, Firefox 1.5, Firefox 2, Firefox 3, Firefox 11, Chrome 17, Opera 11, Safari 5 (para Windows) y desde una BlackBerry y una iPad. En Explorer 6 no hay problema para visualizar la descripción, pero se ve siempre presente como si el javascript estuviera deshabilitado.
HTML
El código HTML es XHTML 1.0 Strict válido y es el siguiente. En primer lugar tenemos la cabecera:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
<head>
<title>Ejemplo descripción extensa accesible de imágenes</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<meta name="author" content="Olga Carreras" />
<meta name="description" content="Descripciones extensas de imágenes accesibles con lectores de pantalla y sin imágenes activas" />
<link href="estilos.css" type="text/css" rel="stylesheet" media="all" />
<script type="text/javascript" src="utils.js"></script>
</head>
Como se ve, estoy llamando a una CSS y a un JS que explico más adelante.
A continuación tenemos el cuerpo de la página:
<body>
<h1>Ejemplo de descripción extensa de una imagen: accesible con lector de pantalla y sin imágenes activas</h1>
<p>Olga Carreras. Ejemplo del artículo <a href="http://olgacarreras.blogspot.com">"Descripción extensa de una imagen: accesible con lector de pantalla y sin imágenes activas"</a></p>
Después de lo que es el título de la página y el enlace al artículo tenemos ya la imagen:
<div>
<img src="razones_uso_tecnologia_accesible.gif" alt="Razones de uso de la tecnología accesible" id="image1" class="images" />
<p><a href="#descripcion" title="Mostrar la descripción de la imagen Razones de uso de la tecnología accesible" id="linkDescripcion" class="oculto">Ver descripción de la imagen</a></p>
</div>
La imagen es un gráfico, por tanto el atributo ALT no es suficiente, necesitamos una descripción detallada la imagen.
Os preguntaréis la razón por la cuál he incluido a continuación de la imagen un enlace "Ver descripción de la imagen".
Ese enlace no es necesario puesto que si la imagen no está cargada se verá la descripción detallada y los lectores de pantalla no van a tener problemas para acceder a dicha descripción.
Sin embargo, puede darse el caso de usuarios con vista cansada o que accedan desde un dispositivo móvil y el tamaño de letra de la imagen les resulte pequeño (y no sepan o no puedan hacer zoom de la imagen)
En ese caso les puede ser de utilidad pulsar el enlace para ver la descripción.
El enlace es un ancla al comienzo de la descripción, después veremos que mediante javascript no intrusivo se le ha asignado una función que permite mostrar/ocultar la descripción detallada y personalizar el texto y el TITLE del enlace en función de si se visualiza o no la descripción.
<div id="descripcion" class="visible">
<h2><abbr title="Flechas que señalan a la imagen">< <</abbr> Descripción de la imagen: Razones de uso de la tecnología accesible</h2>
<h3>Por entorno laboral</h3>
<ul>
<li>Con discapacidad severa: 4%</li>
<li>Con discapacidad moderada: 3%</li>
<li>Sin discapacidad: 6%</li>
</ul>
[el resto de la descripción larga, no la pongo aquí toda]
</div>
Como vemos, a continuación se incluye la descripción detallada correctamente maquetada. Esta descripción se oculta una vez cargada la página mediante javascript no intrusivo, por tanto estará disponible tanto sin javascript activo como sin CSS activas.
Con CSS activas, tanto si pulsas el enlace como si no se carga la imagen, la descripción se posiciona a la derecha de la imagen.
Por otro lado veremos que la descripción extensa se está ocultando de forma accesible, así que los usuarios que usan un lector de pantalla (podéis probarlo con NVDA) escuchan la descripción a continuación de la imagen y el enlace.
<div class="pie">
<p>Probad a deshabilitar javascript, css o imágenes. Para ver sin imágenes cargadas o sin javascript activo acordaros de recargar la página una vez que los desactivéis.</p>
<p>Para facilitaros verla sin la imagen cargada os dejo una copia de la misma página pero donde se ha escrito mal el nombre de la imagen y por tanto no la encuentra: <a href="descripcion_imagenes_accesibles_sinimg.html">Probar esta página cuando no se encuentra la imagen.</a></p>
</div>
</body>
</html>
En el pie de la página os recuerdo que si deshabilitáis el javascript, las CSS o las imágenes mientras visualizáis la página deberéis recargarla. Para facilitaros comprobar que, efectivamente, cuando no se carga la imagen se muestra por defecto la descripción a su lado, os pongo un enlace a una copia de la página donde he escrito mal el nombre de la imagen para comprobar cómo se ve la página sin la imagen cargada.
Como se observa, cuando la imagen no se ha podido mostrar, se ve en el hueco que ocuparía la imagen su ALT, y junto a la imagen aparece por defecto la descripción detallada. Ya no se muestra el enlace "Ver descripción de la imagen" porque no es necesario.
Me parece importante destacar que se ha separado:
- el contenido: eso es únicamente lo que vemos en la página HTML
- la presentación: no se especifica ningún estilo en la página, todos están recogidos en la CSS
- el código javascript: no hay ningún evento, ninguna función, nada que haga sospechar que esta página incluye javascript (salvo la llamada al JS en el HEAD). Todo el javascript, incluso las funciones que se llaman en el onLoad de la página, están definidas de forma no intrusiva.
CSS
La CSS es CSS 2.1 válida. No pongo toda la CSS, sólo aquello que es relevante para el ejemplo.
.oculto{
position:absolute;
left:-999em;
}
Con esta clase general "oculto" oculto aquellos elementos que me interesa:
- al cargarse la página compruebo si la imagen se ha cargado, en cuyo caso oculto por javascript la descripción. Sin javascript activo, por tanto, la descripción se verá.
- el enlace "Ver descripción de la imagen" tiene esta clase "oculto" por defecto y una vez cargada la página lo hago visible. De esta manera, sin javascript activo, el enlace no se muestra puesto que ya no es necesario.
La forma de ocultar (mediante posicionamiento fuera de pantalla) permite que los lectores de pantalla sí puedan acceder al contenido oculto, algo que no ocurre con display:none
. Más detalles en "Ocultar contenido sin comprometer la accesibilidad ni el posicionamiento de la página"
Otros estilos que me interesa comentar son los de la imagen:
.images{
width:auto;
height:auto;
}
.widthImage1{
width:393px;
height:363px;
}
Por defecto indico que el ancho de las imágenes sea "auto". No puedo poner por defecto el tamaño real de la imagen porque el script se basa en comprobar si el ancho de la imagen es diferente del ancho que debería tener, en cuyo caso es que la imagen no está cargada.
Sin embargo tengo una clase con el tamaño real de la imagen porque en Safari y Chrome, si la imagen no tiene especificado su ancho y alto real, no se muestra su atributo ALT. Así que veremos que en el script, tras comprobar el ancho de la imagen para saber si la imagen está cargada, le aplico la clase "widthImage1", y de este modo en Safari y Chrome vemos su ALT.
JS
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
La función "addLoadEvent" es la que nos permite llamar a funciones en el onLoad de la página de forma no intrusiva.
¿Qué funciones estamos llamando? Primero a addLoadEvent(noimage)
var Image1Width=393;
function noimage(){
var objImagen = document.getElementById('image1');
var objDescripcion = document.getElementById('descripcion');
var linkDescripcion = document.getElementById( 'linkDescripcion' );
objDescripcion.className = 'oculto';
linkDescripcion.className = 'visible';
if (objImagen.offsetWidth != Image1Width)
{
objDescripcion.className = 'visible';
objImagen.className = 'widthImage1';
linkDescripcion.className = 'oculto';
}
}
Lo primero que hago, como ya he comentado, es ocultar la descripción larga de la imagen y mostrar el enlace "Ver descripción de la imagen".
A continuación compruebo si el ancho de la imagen es diferente del ancho que debería tener, en cuyo caso es que la imagen no se ha cargado.
En la propuesta de S.Faulkner se comparaba si era igual a 1, pero esto no me funcionaba en todos los navegadores. Por eso lo comparo con el ancho real "393". Es más "sucio" porque no me sirve para todas las imágenes como el compararlo con 1, sino que he de personalizarlo para cada una, pero funciona en todos los navegadores.
Nota: Faulkner lo comparaba con 1 porque no le ponía ALT a las imágenes. Entonces el hueco de la imagen no se adaptaba al ALT y por eso su ancho era 1 cuando no estaba cargada. Como se debe poner ALT tenemos que hacerlo comparándolo con su ancho real. Por otro lado, indicar el ancho y alto de la imagen ayuda a las personas que ven la página sin la imagen cargada a hacerse una idea del tamaño que esta tenía.
En el caso de que la imagen no se haya cargado muestro la descripción, cambio la clase de la CSS aplicada a la imagen (ya he explicado en la CSS que es para que en Chrome y Safari se vea el atributo ALT dentro de la zona de la imagen) y oculto el enlace "Ver descripción de la imagen" porque el enlace ya no es necesario.
La otra función que llamo en el onLoad de la página es la siguiente:
addLoadEvent (function(){
var linkDescripcion = document.getElementById( 'linkDescripcion' );
var objDescripcion = document.getElementById('descripcion');
linkDescripcion.onclick = function(){
if (objDescripcion.className == 'oculto')
{
objDescripcion.className = 'visible';
linkDescripcion.innerHTML="Ocultar descripción de la imagen";
linkDescripcion.title="Ocultar la descripción de la imagen Razones de uso de la tecnología accesible"
}else{
objDescripcion.className = 'oculto';
linkDescripcion.innerHTML="Ver descripción de la imagen";
linkDescripcion.title="Mostrar la descripción de la imagen Razones de uso de la tecnología accesible"
}
}
}
)
Esta función añade al evento "onClick" del enlace "Ver descripción de la imagen" una función que:
- Si la descripción de la imagen está oculta, al pulsar el enlace la mostraremos. Y a continuación cambiaremos el texto del enlace por su nueva acción "Ocultar descripción de la imagen" y cambiaremos también el TITLE de la imagen para que esté acorde con su nueva función de ocultar la descripción.
- Si la descripción de la imagen está visible, al pulsar el enlace la ocultaremos. Y a continuación cambiaremos en texto del enlace por su nueva acción "Ver descripción de la imagen" y cambiaremos también el TITLE de la imagen para que esté acorde con su nueva función de mostrar la descripción.
Algo que no he hecho para que se viera más claro lo que hacían las funciones y que se debería hacer para separar el código javascript del texto concreto que queremos personalizar, sería definir esos literales en un fichero diferente de variables para que nos sean más sencillos de modificar. Así en el código sólo incluiriamos variables y no texto concreto.
Os animo ha que dejéis en los comentarios cualquier sugerencia de mejora o problema que detectéis.
Artículos relacionados:
Muy buen ejemplo Olga, voy a probarlo.
Es muy práctico para mostrar la necesidad de una descripción larga, sobre todo en ese tipo imágenes con gráficas.
No sabía que Safari y Chrome daban problemas al no especificar ancho y alto, voy a realizar también pruebas de esto.
Gracias,
VH
Eliminar comentario de ' Victor Hugo Benitez ' con fecha de 28 de marzo de 2012, 15:50
Al igual que VH, no sabía de esa carencia en Safari y Chrome. Me parece tan evidente y antiguo (ya desde Netscape, creo) que el navegador use los datos width y height sólo para acelerar la carga, pero que si no los encuentra los obtenga de la imagen misma, que me cuesta encontrar motivos para no corregir tal comportamiento. Por suerte soy un usuario feliz de Firefox! :-)
Volviendo a tu artículo, encuentro ingeniosa e impecable la implementación de la solución. Lo que me hace dudar es la necesidad misma de su existencia.
Al menos en casos como el que describes, creo que hubiera sido más económico en tiempo y dinero el mostrar los datos con una tabla en HTML simple, y crear los gráficos con otras herramientas como jQuery Visualize (aquí describen su funcionamiento y puede descargarse).
Siendo así, la detección de si el navegador del usuario tiene o no activada la carga de imágenes, resulta innecesaria.
Saludos.
Eliminar comentario de ' Alfonso Frachelle ' con fecha de 28 de marzo de 2012, 18:44
PD: Tras "imagen misma" me faltó agregar "y cargue todo lo demás como siempre"!
Eliminar comentario de ' Alfonso Frachelle ' con fecha de 28 de marzo de 2012, 19:14
He añadido como mejora la inclusión del texto "Fin de la descripción de la imagen" al final de la descripción larga. De esta manera tanto los usuarios con lectores de pantalla, como aquellos que la visualizan sin CSS, saben cuando termina la descripción.
Eliminar comentario de ' Olga Carreras ' con fecha de 28 de marzo de 2012, 23:32
Excelente entrada Olga, gracias por compartirlo. En Safari iPad funciona... Lo único que me sorprendió es que el enlace al ejemplo me arrojo una ventana nueva ;)
Eliminar comentario de ' Maximiliano ' con fecha de 21 de abril de 2012, 16:25