La detección inapropiada de navegador puede ser la pesadilla del mantenimiento de la web. Re-evaluar los puntos básicos de cuándo y cómo detectar los agentes de usuario (user agents) es crucial para crear un contenido web mantenible y aceptable para múltiples navegadores. Este artículo revisa varias aproximaciones a la detección de navegadores y su utilidad en circunstancias específicas para llegar a una aproximación a la detección de navegadores basada en el sentido común.
Consejo rápido
Para determinar si el usuario visitante está utilizando un navegador basado en Gecko, basta con probar con:
navigator.product == 'Gecko'
o buscar la secuencia:
'Gecko/'
en el navigator.userAgent
. Debe tenerse en cuenta que algunos otros navegadores como Safari incluyen (like Gecko)
en su cadena de agente de usuario y pueden confundir algunas comprobaciones simples.
Introducción
En un mundo ideal se podría escribir HTML, XML, CSS y JavaScript y preocuparse sólo por los estándares de W3C y ECMA. Sin embargo, no vivimos en tal mundo por el momento. Debido a fallos, implementaciones incompletas de los estándares y navegadores anticuados, los desarrolladores web deben ser capaces de determinar qué navegador está usando un visitante y proporcionar el contenido y código script apropiado.
Aunque la detección del navegador es quizás la tarea de script más común que aborda cualquier desarrollador web, parece que la variedad de diferentes estrategias en uso para detectar navegador es ilimitada. Como miembro del equipo de evangelismo de Netscape que ha pasado más de un año investigando el contenido web, puedo decir sin duda que la mayoría de los problemas de compatibilidad encontrados en la web hoy en día se deben a una falta de comprensión de los estándares combinada con estrategias de detección de navegadores inadecuada e inapropiada.
Este artículo intenta proporcionar una visión superficial de las estrategias y buenas prácticas de detección de navegadores. Para recomendaciones más específicas, puede leer el Manual de Compatibilidad de Gecko.
Gecko
Aunque muchos desarrolladores web conocen Firefox, los navegadores de Mozilla y Netscape 6/7, muchos menos son conscientes de que estos navegadores son miembros de una familia completa de agentes de usuario basados en Gecko layout engine que incluyen el navegador comercial CompuServe 7, y navegadores de código abierto como Epiphany, Galeon, Camino, y Kmeleon.
Gecko se diseñó desde el principio para cumplir con los estándares del W3C HTML, W3C CSS, W3C XML, W3C DOM, y ECMAScript (JavaScript). También incluye características de compatibilidad que permiten gestionar razonablemente el contenido heredado que se desarrolló para generaciones anteriores de navegadores como Nescape Navigator 4 así como características que proporcionan compatibilidad con Internet Explorer 5 y 6. A diferencia de otros navegadores, Gecko es realmente un navegador para múltiples plataformas y proporciona idéntica cobertura en todos los sistemas operativos donde está admitido.
La manera más fácil de tratar correctamente Gecko es crear contenido que sólo use los estándares. Desafortunadamente, ningún otro navegador implementa los estándares de una manera tan completa como Gecko, lo que quiere decir que los autores y desarrolladores web se ven forzados a continuar proporcionando cobertura a otros navegadores que no admiten los estándares tan bien. Afortunadamente, otros navegadores como Opera 7/8, y en menor medida Internet Explorer 5 y 6 para Windows e Internet Explorer 5 para Macintosh también implementan los estándares hasta cierto punto. Estos otros navegadores también parecen estar avanzando hacia una implementación más completa y rigurosa de los estándares y se espera que, en el futuro, los autores y desarrolladores web podrán olvidarse de la detección de navegadores al menos en lo relativo a las características gobernadas por estándares.
Aún se debe resolver cómo desarrollar contenido basado en estándares sin dejar de aprovechar las diferentes implementaciones de los navegadores modernos y, al mismo tiempo, admitir (en menor grado) los navegadores más antiguos y capaces. La detección de navegadores es clave para cumplir esta tarea.
Resumen de la historia de la detección de navegadores
Para entender por qué muchas estrategias comunes de detección de navegadores son inapropiadas, hay que referirse primero a cómo surgieron estas estrategias.
En los primeros días de la web, HTML era muy simple, no estandarizado y no incluía ninguna capacidad para scripts del lado cliente. HTML en sí mismo no se estandarizó hasta que se presentó HTML 2.0 a finales de 1995 y ni siquiera incluía tablas. Los suministradores de navegadores como Netscape y Microsoft competían para añadir características atractivas al HTML que implementaban en sus navegadores para proporcionar el contenido más atractivo y rico a sus usuarios e inducir a los autores web a hacer uso de ello. Las capacidades de los navegadores para incluir lo último y mejor en contenidos cambiaban casi diariamente.
Los autores web se encontraron desde el principio con una variedad de navegadores, algunos de los cuales implementaban la mejor y última versión de HTML y algunos que no lo hacían. La solución era o bien proporcionar el mínimo común denominador de HTML o usar técnicas de detección de navegadores en el servidor web para enviar contenido personalizado a cada navegador dependiendo del grado de implementación que proporcionaba éste. Acababa de nacer la detección de navegadores en el lado del servidor usando las cadenas de agente de usuario.
Las cadenas de agente de usuario se definen en el protocolo HTTP y están disponibles para los servidores web (refiérete al RFC 1945 - Hypertext Transfer Protocol 1.0 and RFC 2068 - Hypertext Transfer Protocol 1.1).
La aproximación más común en este momento era distinguir los agentes de usuario por vendor (suministrador) y version (versión) usando la cadena de agente de usuario recibida. Aunque esta aproximación se consideraba razonable en aquel momento, causó problemas a los suministradores de navegadores desde el principio. Los navegadores Netscape originales usaban una cadena de usuario que comenzaba con el nombre en clave del navegador Netscape seguido por su número de versión, p.e. Mozilla/version
seguido por un token de comentario que daba información adicional relativa al sistema operativo usado, etc. Puesto que las primeras técnicas de detección de navegadores se basaban en buscar un navegador basado en Netscape y sólo proporcionaban contenido personalizado a los navegadores que usaban la cadena de usuario Mozilla/version
, otros suministradores hicieron norma el uso de Mozilla/version
para indicar que eran compatibles con una versión en concreto de Netscape. Ya que otros navegadores fingían ser navegadores Netscape y codificaban su información de versión de una manera no estándar en el área de comentarios del agente de usuario, la tarea de determinar qué navegador se estaba usando se convirtió en más complicada de lo que debía haber sido.
Netscape Navigator 2 introdujo la capacidad de ejecutar JavaScript en los navegadores web. A medida que la evolución de los navegadores continuó, aparecieron las diferencias en la implementación del script y los objetos admitidos por el navegador. Los autores web ya no debían sólo detectar los navegadores web en sus servidores web, sino que podían ahora ejecutar scripts en el lado cliente (en el mismo navegador) que podían usarse para distinguir navegadores. Una de las primeras aproximaciones a la detección de navegadores en el lado cliente incluía probar si el navegador implementaba determinados objetos. Un ejemplo de esta aproximación era probar la existencia del objeto document.images
.
Aunque la detección basada en objetos se usó en algunas circunstancias, muchos autores web continuaron usando la aproximación vendor/version para distinguir navegadores web en sus scripts del lado cliente. Puesto que la cadena de agente de usuario era accesible como una propiedad del objeto navigator
(p.e. navigator.userAgent
), muchos autores web usaron la misma lógica en sus scripts del lado cliente que ya habían usado anteriormente en el lado del servidor. Además de navigator.userAgent
estaban disponibles otras propiedades como appName
y appVersion
en el objeto navigator
que podían usarse en las estrategias de detección de navegadores vendor/version.
El ejemplo clásico de esta estrategia de detección vendor/version en el lado cliente puede encontrarse en el Ultimate Browser Sniffer. Este script y variantes del mismo pueden encontrarse hoy en día en muchos sitios web, donde es una fuente común de problemas de detección.
Netscape Navigator 4 e Internet Explorer 4 introdujeron la capacidad de manipular el contenido HTML en un navegador (Dynamic HTML o DHTML) en lugar de en el servidor web y comenzaron la introducción de las implementaciones de CSS para proporcionar estilos al contenido. Esta generación de navegadores, además de compartir varias características que no estaban disponibles en versiones previas, implementaban cada una su propias (e incompatibles) capacidades competidoras para manipular contenido en una página web.
Dado que los navegadores de cada suministrador implementaban diferentes objetos para ejecutar DHTML, los autores web comenzaron a usar la detección de objetos para distinguir vendor/version a través de la existencia de objetos JavaScript concretos. La existencia de document.layers
era suficiente para estar seguro de que el navegador era Netscape Navigator 4 mientras que la existencia de document.all
era suficiente para estar seguro de que el navegador era Microsoft Internet Explorer 4. Una suposición implícita que muchos autores web de esa época hacían era que sólo había dos tipos de navegadores disponibles... Netscape Navigator y Microsoft Internet Explorer.
Estas estrategias de clasificar los navegadores por vendor/version, asumiendo que los únicos navegadores en uso eran Netscape Navigator 4 o Internet Explorer 4 falló cuando aparecieron navegadores alternativos como los basados en Gecko. Muchos de los problemas informados en la prensa sobre la incapacidad de Gecko de mostrar contenido estaban directamente relacionados con estrategias de detección de navegadores inadecuadas e inapropiadas.
Una nota final en las estrategias vendor/version. Un desarrollador web que use completamente la detección y distinciones de navegador en el Ultimate Browser Sniffer producirá código que usa bifurcaciones de código para muchos navegadores y versiones. Imagine intentar mantener un sitio web que use muchas de las variables disponibles de Ultimate Browser Sniffer.
suministrador del navegador | is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV |
número de versión del navegador | is_major (integer que indica el número de versión mayor: 2, 3, 4 ...), is_minor (float que indica el número de versión completo: 2.02, 3.01, 4.04 ...) |
suministrador Y número de version mayor del navegador | is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3, is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up, is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up |
número de versión de JavaScript | is_js (float que indica el número completo de versión de JavaScript: 1, 1.1, 1.2 ...) |
plataforma y versión de SO | is_win, is_win16, is_win32, is_win31, is_win95, is_winnt, is_win98, is_winme, is_win2k, is_os2, is_mac, is_mac68k, is_macppc, is_unix, is_sun, is_sun4, is_sun5, is_suni86, is_irix, is_irix5, is_irix6, is_hpux, is_hpux9, is_hpux10, is_aix, is_aix1, is_aix2, is_aix3, is_aix4, is_linux, is_sco, is_unixware, is_mpras, is_reliant, is_dec, is_sinix, is_freebsd, is_bsd, is_vms |
¡Detectar navegadores usando este nivel de detalle es inmanejable, inmantenible y viola los principios básicos de la autoría web! Se recomienda profundamente a todo el mundo que evite esta trampa.
Problemas causados por una detección inapropiada del navegador
Exclusión de navegadores desconocidos
Si en su lógica de detección sólo proporciona pruebas para navegadores específicos, su sitio no será utilizable en caso de que un visitante use un navegador diferente. Considere el siguiente ejemplo:
// PROCEDIMIENTO ERRÓNEO - no usar! if (document.all) { // Internet Explorer 4+ document.write('<link rel="stylesheet" type="text/css" src="style-ie.css">'); } else if (document.layers) { // Navigator 4 document.write('<link rel="stylesheet" type="text/css" src="style-nn.css">'); }
Observe cómo el ejemplo anterior sólo proporcionaba hojas de estilo para Internet Explorer y Navigator 4, e incluso así sólo si el visitante tiene JavaScript activado en su navegador. Los usuarios de Netscape 6, Netscape 7, CompuServe 7, Mozilla, Opera no podrán ver el sitio correctamente.
Interpretación errónea de los navegadores
Un error común que hacen los autores web es asumir que si un navegador no es Netscape Navigator 4, ha de ser Internet Explorer y viceversa. Por ejemplo:
// PROCEDIMIENTO ERRÓNEO - no usar! if (document.all) { // Internet Explorer 4+ elm = document.all['menu']; } else { // Se asume Navigator 4 elm = document.layers['menu']; }
Observe cómo el ejemplo anterior asumía que cualquier navegador que no sea Internet Explorer ha de ser Navigator 4 e intentaba usar Layers. Éste es un origen común de problemas al usar navegadores basados en Gecko así como Opera. Un error similar puede verse en el siguiente ejemplo:
// PROCEDIMIENTO ERRÓNEO - no usar! if (document.layers) { // Navigator 4 elm = document.layers['menu']; } else { // Se asume Internet Explorer 4+ elm = document.all['menu']; }
Netscape 6 fue el primer navegador comercial publicado basado en Gecko. Debido a una falta de comunicación y comprensión, muchos sitios han creado estrategias de detección inapropiadas basadas en la cadena de agente de usuario de Netscape 6. La cadena de agente de usuario de Netscape 6 sigue los estándares HTTP para especificar la versión del agente de usuario (véase Mozilla user-agent strings y Cadenas de agente de usuario de Gecko).
Mozilla/5.0 (...) Gecko/20001108 Netscape6/6.0
El primer par suministrador/versión (Mozilla/5.0) indica que Netscape 6 es un navegador de quinta generación y que no es idéntico a los navegadores anteriores. Todos los navegadores basados en Gecko devuelven actualmente Mozilla/5.0 como su versión primaria aunque ningún otro navegador lo hace así en este momento. Se confía en que, cuando otros suministradores de navegadores alcancen el mismo nivel de cumplimiento de estándares que Gecko y comiencen a eliminar la compatibilidad con navegadores antiguos, ellos también comenzarán a informar que su versión es 5. Asumir que únicamente Gecko usa Mozilla/5.0 hará que su lógica de detección de navegadores falle tan pronto como otro suministrador publique un navegador que devuelva Mozilla/5.0.
El segundo par suministrador/versión (Gecko/20001108) identifica Netscape 6 como una versión concreta de Gecko que se compiló el 8 de noviembre de 2000. Si debe detectar Gecko usando la cadena de agente de usuario, Gecko/CCYYMMDD es la cadena más adecuada a buscar.
El tercer par suministrador/versión (Netscape6/6.0) identifica esta instancia en particular de un navegador Gecko como Netscape 6.0. Muchos sitios se centraron en la existencia de la cadena Netscape6 en el agente de usuario y usaron comprobaciones similares a:
if (navigator.userAgent.indexOf('Netscape6') != -1) { // Netscape 6 code }
Observe cómo este tipo de detección obvia cualquier otro navegador basado en Gecko. Desafortunadamente, la cadena de agente de usuario de Netscape 6 no era suficientemente generalizable debido a su uso de la cadena Netscape6 como descripción del suministrador. Netscape 7 corrige este error e introduce otra posibilidad de que falle la detección basada en la cadena de agente de usuario.
Mozilla/5.0 (...) Gecko/200207XX Netscape/7.0
Observe cómo Netscape 7 ya no usa la cadena Netscape6 como suministrador. Cualquier estrategia de detección de cadena de usuario para Gecko basada en la existencia de la cadena Netscape6 fallará si el navegador es Netscape 7.
Utilización de objetos JavaScript para determinar el suministrador/versión (vendor/version)
Como ya se ha discutido, una aproximación común en el pasado fue usar objetos para clasificar los navegador por suministrador/versión. Un tipo común de detección que originalmente se escribió para identificar únicamente Netscape Navigator 4 e Internet Explorer 4 podría tener este aspecto:
// PROCEDIMIENTO ERRÓNEO - no usar! if (document.all) { // IE4 height = document.body.offsetHeight; } else if (document.layers) { // NN4 height = window.innerHeight; } else { // other height = 0; }
Con la introducción de DOM de W3C, el método estándar document.getElementById
pasó a estar disponible en Internet Explorer 5 y más tarde en Netscape 6 (Gecko). Muchos autores web decidieron que la manera más fácil de identificar Netscape Gecko era añadir otra bifurcación de código como sigue:
// PROCEDIMIENTO ERRÓNEO - no usar! if (document.all) { // IE4 height = document.body.offsetHeight; } else if (document.layers) { // NN4 height = window.innerHeight; } else if (document.getElementById) { // Creen que esto es Gecko // ¡pero podrían estar equivocados! height = window.innerHeight; } else { // Otros height = 0; }
La aproximación es incorrecta ya que asumen que el único otro navegador además de Internet Explorer 5+ que implementa document.getElementById
es Gecko. Esto no es cierto hoy en día y será cada vez menos cierto a medida que aparezcan más navegadores en el futuro que implementen los estándares DOM de W3C.
Recomendaciones
Centrarse en los estándares y no en navegadores concretos
Si bien el período de 1994 a 2000 estuvo dominado por navegadores incompatibles y no estándares de Netscape y Microsoft, ahora el factor dominante en el desarrollo web son los estándares propuestos por el World Wide Web Consortium (W3C). Los estándares son importantes para los desarrolladores web debido al incremento de la flexibilidad, potencia de presentación y ayudas a los usuarios con alguna discapacidad, por citar sólo algunas razones.
Orientar el contenido de una web a suministradores concretos ignora la posibilidad de que puedan aparecer otros navegadores que implementen los mismos estándares en el futuro. Un problema común en la web hoy en día es la suposición de que los únicos navegadores en el mundo son Netscape Navigator y Microsoft Internet Explorer. Esto ignora la existencia de Opera así como los dispositivos de mano más modernos que se están usando para acceder a la web ahora y en el futuro.
Los navegadores basados en Mozilla (como Firefox), Internet Explorer 6 en Windows, e Internet Explorer 5 para Macintosh implementan todos ellos DOCTYPE switching. Ésta es una técnica por la cual estos navegadores pueden cambiar de un modo con "veriecuetos" ("Quirks" mode) (que emula las implementaciones con errores de los navegadores de generaciones anteriores) a un modo de estándares (que se adhiere más estrictamente a los estándares). Para los contenidos nuevos, se recomienda el uso de un DOCTYPE que invoque el modo de estándares en Gecko e Internet Explorer 6. Esto asegurará que sus diseños funcionen de manera similar en estos navegadores así como en otros navegadores que implementen los estándares.
Proporcionar una alternativa a los navegadores desconocidos
Proporcione siempre contenido y bifurcaciones de código para los navegadores desconocidos. La aproximación recomendada es asumir que cualquier navegador no conocido implementa los estándares básicos de HTML y CSS y hasta cierto nivel JavaScript y DOM de W3C. Esto garantizará que su contenido será admitido hoy y en el futuro por cualquier navegador que implemente los estándares.
Limitar el uso de características específicas de un suministrador/versión
Crear contenido que sea conforme a los estándares es la manera más fácil de dar cobertura al rango más amplio posible de agentes de usuario y decrementar sus costes de mantenimiento. Aunque no siempre es posible evitar las diferencias entre valores específicos de suministrador/versión de varios navegadores, el uso de tales características y la distinción entre navegadores basada en valores de suministrador/versión debería estar estrictamente limitada a aquellas áreas donde aún se requiera.
Limitar el uso de detección basada en la cadena de agente de usuario
La detección de navegadores en el lado del servidor requiere el uso de cadenas de agente de usuario. Recomendamos que el uso de la detección basada en cadenas de agente de usuario se limite a situaciones en el lado del servidor y únicamente a aquellas circunstancias donde es absolutamente necesario, como cuando es preciso obtener detalles de la rama de Gecko.
Hay razones legítimas para usar la cadena de agente de usuario (o el objeto navigator
) para determinar exactamente qué suministrador, versión o sistema operativo se está usando. Muchos sitios financieros (bancos, firmas que operan en bolsa online, etc.) tienen políticas muy estrictas con respecto a qué navegadores prestan asistencia. Esto se debe al historial de problemas de seguridad que se han descubierto en navegadores antiguos. Si tiene la necesidad de permitir sólo a algunas versiones concretas de navegadores que usen su sitio seguro, entonces la cadena de agente de usuario y la información relacionada del objeto navigator
pueden resultar muy útiles.
También puede usar información detallada con respecto a la versión de un navegador para solventar fallos en versiones específicas de un navegador. Sin embargo, esto puede derivar rápidamente en una pesadilla para el mantenimiento si no es cuidadoso. Se recomienda que tome estas medidas sólo con carácter temporal y, tan pronto como se corrijan en versiones más modernas del navegador, que requiera a sus visitantes que actualicen éste.
Proporcionar páginas básicas para los navegadores más antiguos
Ningún sitio web comercial de hoy en día considera un requisito que se visualice correctamente en Netscape Navigator versiones 1, 2 o 3, o Microsoft Internet Explorer 3. Las razones son que las capacidades de esos navegadores son demasiado limitadas comparadas con los navegadores más modernos, los requerimientos añadidos de desarrollo y control de calidad incrementan demasiado el coste de desarrollo de los sitios web y la cuota de mercado de tales navegadores no justifica el coste de tenerlos en cuenta.
Una de las decisiones más importantes que puede tomar de cara a mejorar la calidad de su sitio y reducir los costes de desarrollo, mantenimiento y control de calidad es proporcionar sólo una atención limitada a los navegadores más antiguos tales como Netscape Navigator 4 e Internet Explorer 4. Una de las aproximaciones más comunes en los sitios web más importantes es proporcionar una versión de bajo nivel de una página web a los navegadores más antiguos a la vez que proporciona una página más rica que usa CSS y JavaScript avanzados a los navegadores más modernos. Esto puede conseguirse mediante la detección del navegador en el lado del servidor, ya sea como parte de una solución basada en scripts o como parte de la capacidad nativa del servidor web de proporcionar diferente contenido a diferentes agentes de usuario. Esta aproximación no requiere necesariamente que prepare páginas separadas para los navegadores modernos y los más simples. Una solución común es escribir el contenido en un formato neutral como XML y usar transformaciones XSLT para generar el HTML necesario para cada clase de navegador.
El que un navegador en concreto debe recibir la versión de bajo nivel depende hasta cierto punto de qué características de JavaScript o CSS se estén usando en el contenido avanzado. Netscape Navigator e Internet Explorer 4 deberían considerarse ambos navegadores de bajo nivel para la mayoría de las páginas debido a su limitada implementación de los estándares basados en CSS y el más reciente DOM. Si sus páginas hacen uso de JavaScript avanzado que manipula o crea nuevo contenido usando la especificación DOM Core de W3C, entonces Opera 5 y 6 también deben considerarse de bajo nivel debido a su limitada implementación de DOM de W3C.
El futuro pertenece a los desarrolladores y navegadores que implementen los estándares. Si deja de sacar partido a los cambios que se avecinan en los navegadores, los competidores se comeran su comida. Cuando eso suceda, el único lugar en el que se podrá encontrar su sitio web es en el archivo web.
Usar detección no basada en script cuando sea posible
Los navegadores más antiguos tienen muchas limitaciones que hacen que ignoren las características más avanzadas. El uso juicioso de estas limitaciones en los navegadores más antiguos le permitirá incluir contenido moderno sin dejar de prestar asistencia a los navegadores antiguos.
HTML proporciona varios métodos para detectar si una implementación incluye diversas características como scripts y marcos. Use estas capacidades naturales de HTML para extender el abanico de navegadores admitido por el contenido de su web.
Usar NOFRAMES para dar cobertura a los navegadores que no implementan marcos
<HTML> <HEAD> <TITLE>Marcos</TITLE> </HEAD> <FRAMESET ROWS="30,*"> <FRAME SRC="foo.html"> <FRAME SRC="bar.html"> <NOFRAMES> <BODY> <P> Esta página requiere marcos. Vea el mapa de sitio: <a href="noframes.html"></a>. </P> </BODY> </NOFRAMES> </FRAMESET> </HTML>
Usar NOSCRIPT para dar cobertura a los navegadores que no permiten el uso de scripts
Algunos navegadores pueden no implementar scripting, y algunos usuarios pueden tener los scripts desactivados en sus navegadores. Use la etiqueta NOSCRIPT para proporcionar a esos usuarios versiones alternativas de sus páginas que no usen scripts, o al menos notificarles de la necesidad de permitir la ejecución de scripts para poder visualizar su contenido correctamente.
Dado que navegadores tales como Netscape Navigator 4 e Internet Explorer 4 no implementan algunas de las adiciones más recientes al estándar JavaScript (ECMAScript), a menudo es necesario limitar el uso las características avanzadas de JavaScript tales como el procesamiento de excepciones. Una aproximación es requerir que los usuarios de navegadores que no admitan el nivel de JavaScript usado en su contenido desactiven JavaScript para poder usar su contenido. Puede hacer esto proporcionando un mensaje de error a los usuarios de navegadores más antiguos así como un contenido alternativo incluido en las etiquetas NOSCRIPT.
<HTML> <HEAD> <TITLE>Sin script ('noscript')</TITLE> </HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> window.onerror = function () { // Envía al usuario a una página describiendo las limitaciones // del navegador y le indica que tiene que desactivar // JavaScript para poder ver su sitio. } // Netscape Navigator 4 generará un error en cualquier // JavaScript que intente usar procesamiento de excepciones // con bloques try ... catch. try { // Código para implementar un menú bonito } catch (errores) { // Manejo de excepciones } </SCRIPT> <NOSCRIPT> <!-- Si JavaScript no está activado, entonces el navegador mostrará los contenidos de la etiqueta NOSCRIPT que, en este caso, es un simple menú implementado como una lista no ordenada. --> <UL> <LI><A HREF="choice1.html">Elección 1</A></LI> <LI><A HREF="choice2.html">Elección 2</A></LI> </UL> </NOSCRIPT> </BODY> </HTML>
Usar SCRIPT LANGUAGE para elegir el navegador en el que se ejecuta
La elección del lenguaje de scripting viene determinada por el atributo LANGUAGE de la etiqueta script. Internet Explorer 4 y superiores pueden admitir una variedad de lenguajes de script. Los más comunes son VBSCRIPT y JavaScript. Internet Explorer también usa JSCRIPT como un sinónimo de JavaScript. Puesto que otros navegadores no admiten los valores VBSCRIPT o JSCRIPT como atributo de lenguaje, puede usar éstos cuando desee que ciertos scripts se ejecuten únicamente por Internet Explorer 4 y superior.
<HTML> <HEAD> <TITLE>Lenguajes Script</TITLE> </HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> // Código JavaScript para implementar un menú vistoso // Visible a todos los navegadores que admitan JavaScript </SCRIPT> <SCRIPT LANGUAGE="JScript"> // Código JavaScript que usa características propietarias de // Internet Explorer no disponibles en otros navegadores </SCRIPT> <SCRIPT LANGUAGE="VBScript"> // Codigo VBScript que usa características propietarias de // Internet Explorer no disponibles en otros navegadores </SCRIPT> </BODY> </HTML>
Usar las limitaciones CSS de Netscape Navigator 4
Es posible usar las limitaciones de Netscape Navigator 4 en su implementación CSS para excluir automáticamente ciertas reglas CSS de su interpretación por Navigator 4.
Por ejemplo, Navigator 4 no comprende la directiva @import en CSS y no cargará ninguna hoja de estilo CSS externa especificada vía @import. Esta técnica puede usarse para proporcionar reglas CSS básicas comunes para todos los navegadores (incluyendo Navigator 4) y, al mismo tiempo, proporcionar reglas más avanzadas en un archivo CSS externo para los navegadores más modernos con mejor cumplimiento CSS.
<STYLE type="text/css"> /* Reglas CSS para Navigator 4 */ </STYLE> <STYLE type="text/css"> /* Reglas CSS avanzadas ignoradas por Navigator 4 */ @import "advanced.css"; </STYLE>
Hay disponible una técnica similar para ocultar las reglas CSS de Navigator 4 aprovechando el hecho de que Navigator 4 ignorará las reglas CSS que aparezcan tras la secuencia /*/*/ en una hoja de estilos.
<STYLE type="text/css"> /* Reglas para Navigator 4 */ /*/*/ /* Reglas CSS avanzadas ignoradas por Navigator 4 */ </STYLE>
DevEdge usa esta técnica para ocultar el CSS avanzado de Navigator 4.
Usar detección de objetos orientada a características
La detección de objetos es un poderoso método para proporcionar cobertua a múltiples navegadores en su contenido web. Aunque puede usar la detección de objetos como un medio más para distinguir entre distintos suministradores y versiones, la técnica muestra su verdadero potencial cuando se usa para detectar características en lugar de navegadores.
La detección de objetos orientada a características consiste en comprobar la existencia de objetos específicos antes de intentar usarlos en un script. El ejemplo clásico es:
if (document.images) { // código que procesa las imágenes }
La ventaja de la detección de características es que funcionará con independencia del suministrador y versión. Podemos reescribir el ejemplo anterior que ilustraba los problemas de usar objetos para determinar el suministrador y versión para que use en su lugar detección de características.
if (document.body && typeof(document.body.offsetHeight) == 'number') { height = document.body.offsetHeight; } else if (typeof(window.innerHeight) == 'number') { height = window.innerHeight; } else { height = 0; }
Observe cómo el ejemplo anterior no hace suposiciones sobre qué navegador se está usando. En su lugar, sólo comprueba los objetos que desea usar. Puesto que los valores numéricos podrían ser cero, el script prueba el tipo de los objetos para asegurarse de que son números.
Gecko y Navigator 4
Gecko es el reemplazo para el motor de dibujado de Navigator 4 y, como tal, retiene muchas características de Navigator 4. Las diferencias básicas entre Navigator 4 y Gecko pueden resumirse rápidamente en:
- Gecko cumple con los estándares. Gecko implementa muchos más estándares que Navigator 4 y los implementa correctamente, a diferencia de Navigator 4.
- Gecko no implementa capas (Layers). Navigator 4 introdujo la API de capas que usaba para manipular contenido y que formaba la base de DHTML en Navigator 4. Las capas, sin embargo, no fueron aceptadas por W3C ni en HTML ni en DOM. Dado que la misión de Gecko era ser el navegador más conforme a estándares posible, no se implementaron las capas. Esta falta de compatibilidad hacia atrás ha sido la causa de muchos problemas para los autores web, pero puede solucionarse fácilmente a través de un buen contenido y las estrategias de detección de navegadores correctas. A medida que el uso de Navigator 4 decrece y más autores usan los estándares en sus contenidos, las capas y los problemas que causan desaparecerán.
Gecko e Internet Explorer
Gecko implementa cierto número de características propietarias de Internet Explorer, especialmente con respecto a su modelo de objetos DHTML. La implementación en Gecko de las características de IE se ha ido incrementando paulatinamente desde la presentación de Netscape 6 en noviembre de 2000. La mejor aproximación para sacar partido de estas características de compatibilidad con IE en Gecko es usar la detección de características basada en objetos. Esto usará automáticamente esas características en Gecko si están disponibles en la versión de Gecko usada. Vea la DOM Client Object Cross-Reference:navigator para más detalles sobre qué objetos y propiedades de Internet Explorer están implementadas en qué versiones de Gecko.
Ciertas características de Internet Explorer no están implementadas en Gecko. Entre éstas se incluyen el objeto window.event
, behaviors, filtros, transiciones y ActiveX.
Cómo (y cuándo) usar el objeto navigator al detectar Gecko
A menos que necesite específicamente detectar si se está usando Gecko, no use estos métodos. Sólo deberían usarse en circunstancias que no puedan ser resueltas usando la detección de características mediante objetos como, por ejemplo, cuando deben excluirse versiones específicas de Gecko por razones de seguridad.
Nota: para la detección en el lado cliente, recomendamos usar el objeto navigator
y sus propiedades. Toda la información devuelta en el objeto navigator
también está disponible en la cadena de agente de usuario que puede usarse en el lado del servidor.
Producto (product)
navigator.product
es específico de los navegadores Gecko y siempre devolverá 'Gecko'. Ésta es una manera rápida y sencilla de determinar que un navegador está basado en Gecko.
Etiqueta de la rama CVS (CVS Branch Tag)
A partir de Gecko 0.9.0 (Netscape 6.1 en Gecko 0.9.2), navigator.userAgent
contiene la etiqueta de la rama CVS del código fuente usado para crear la versión de Gecko usada en el navegador. La etiqueta de la rama está incluida en el área de comentario de la cadena de agente de usuario y está precedida de la secuencia 'rv:'. En el ejemplo siguiente, la etiqueta de la rama es a.b.c.
Mozilla/5.0 (...; rv:a.b.c) Gecko/CCYYMMDD Suministrador/versión
Los navegadores Gecko compilados desde la misma rama comparten la misma versión básica de Gecko y pueden tratarse de manera similar en lo relativo a HTML, CSS, JavaScript, etc. Por ejemplo, Netscape 6.2, 6.2.1, 6.2.2, 6.2.3 y CompuServe 7 están, todos ellos, compilados a partir de la rama 0.9.4 y, por tanto, tienen el mismo comportamiento en muchos aspectos.
Navegador | Etiqueta de rama |
---|---|
Netscape 6.0 | contenía M18 en lugar del valor rv |
Netscape 6.1 | 0.9.2 |
Netscape 6.2 | 0.9.4 |
Netscape 6.2.1 | 0.9.4 |
Netscape 6.2.2 | 0.9.4.1 |
Netscape 6.2.3 | 0.9.4.1 |
CompuServe 7 | 0.9.4.2 |
Netscape 7.0 | 1.0.1 |
Netscape 7.01 | 1.0.2 |
Como puede ver, todas las versiones de Netscape 6.2 y CompuServe 7 fueron creadas de la rama 0.9.4. La distinción entre 0.9.4, 0.9.4.1, 0.9.4.2 es menor.
Nota: la etiqueta de la rama es una cadena y puede contener más cosas que dígitos sueltos en un nivel concreto. Por ejemplo, es concebible que algún día existan etiquetas de ramas similares a 2.2.0 y 2.12.36. Puesto que estos valores son cadenas, no es posible realizar comparaciones entre cadenas para determinar qué rama es posterior. En nuestro ejemplo, la rama 2.2.0 se creó antes que la 2.12.36, pero una comparación de esos valores entre cadenas mostrará que '2.2.0' > '2.12.36'. La función JavaScript geckoGetRv() proporciona una solución a este problema convirtiendo la etiqueta de la rama en la cadena de agente de usuario en un número de coma flotante donde cada nivel de la etiqueta de la rama es considerado un número entre 0-99.
Etiqueta de rama | geckoGetRv() |
---|---|
0.9.2 | 0.0902 |
0.9.4 | 0.0904 |
0.9.4.1 | 0.090401 |
0.9.4.2 | 0.090402 |
1.0.1 | 1.0001 |
1.0.2 | 1.0002 |
2.2.0 | 2.02 |
2.12.36 | 2.1236 |
geckoGetRv() devuelve valores que pueden compararse usando mayor que, menor que, etc. geckoGetRv() no es parte oficial de Gecko; sin embargo, se proporciona como un ejemplo de aproximaciones que pueden tomarse para comparar las diferentes etiquetas de rama hoy y en el futuro.
Fecha de compilación
navigator.productSub
es específico de los navegadores Gecko y devolverá una cadena que contiene la fecha en que se compiló el navegador en el formato CCYYMMDD (p.e. '20020801' para el 1 de agosto de 2002). Si le preocupa un problema de seguridad concreto en Gecko y sabe, por ejemplo, que todos los navegadores Gecko contienen una corrección para el problema a partir de una cierta fecha, puede comprobar que el valor de navigator.productSub
es posterior a esa fecha.
También puede distinguir entre versiones "punto algo" usando una combinación de la etiqueta de la rama y la fecha de compilación. Por ejemplo, Netscape 6.2.2 y Netscape 6.2.3 tienen ambos la etiqueta de la rama 0.9.4.1, pero Netscape 6.2.2 tiene navigator.productSub == '20020314'
mientras que Netscape 6.2.3 tiene navigator.productSub == '20020508'
.
El suministrador y la versión (vendor/version)
Todos los navegadores Gecko devuelven el suministrador y la versión tanto en el objeto navigator
como en la cadena de agente de usuario. La información de suministrador y versión, no obstante, no es tan útil como la etiqueta de la rama y la fecha de compilación y no recomendamos su uso. Sin embargo, si lo desea, puede distinguir los diferentes tipos de navegador Gecko usando estos valores. Como vimos previamente, el suministrador/versión aparece en la cadena de agente de usuario a continuación de la versión de Gecko.
Mozilla/5.0 (...; rv:a.b.c) Gecko/CCYYMMDD Suministrador/versión
El suministrador está disponible en el objeto navigator
como navigator.vendor
mientras que la versión del suministrador está disponible como navigator.vendorSub
.
Navegador | Suministrador | Versión |
---|---|---|
Netscape 6.0 | Netscape6 | 6.0 |
Netscape 6.01 | Netscape6 | 6.01 |
Netscape 6.1 | Netscape6 | 6.1 |
Netscape 6.2 | Netscape6 | 6.2 |
Netscape 6.2.1 | Netscape6 | 6.2.1 |
Netscape 6.2.2 | Netscape6 | 6.2.2 |
Netscape 6.2.3 | Netscape6 | 6.2.3 |
CompuServe 7.0 | CS 2000 7.0 | 7.0 |
Netscape 7 Versión preliminar 1 | Netscape | 7.0b1 |
Netscape 7.0 | Netscape | 7.0 |
Netscape 7.01 | Netscape | 7.01 |
Ejemplos
Si es como yo, aprende mejor de ejemplos. Estudiar cómo usan otros autores la detección de navegador y las técnicas de codificación para múltiples navegadores es la mejor forma de aprender.
Ejemplo 1 - detección de características basada en objetos
Este ejemplo ilustra el uso de la detección de características. Observe que Gecko 1.0 (Netscape 7) y posteriores implementan la característica propietaria de Internet Explorer clientWidth mientras que Netscape 6 no lo hacía. En este ejemplo, Netscape 7 e Internet Explorer 5+ usarán automáticamente clientWidth mientras que Netscape Navigator 4, Netscape 6, CompuServe 7 y Opera usarán innerWidth.
Compare cómo habría tenido que codificar esto mismo usando aproximaciones de detección basadas en suministrador/versión.
if (windowRef.document.body && typeof(windowRef.document.body.clientWidth) == 'number') { // Gecko 1.0 (Netscape 7) e Internet Explorer 5+ width = windowRef.document.body.clientWidth; } else if (typeof(windowRef.innerWidth) == 'number') { // Navigator 4.x, Netscape 6.x, CompuServe 7 y Opera width = windowRef.innerWidth; }
Ejemplo 2 - detección de características basada en objetos
Cobertura a múltiples navegadores
Este ejemplo también ilustra el uso de la detección de características y muestra las complicaciones que pueden surgir de las implementaciones no estándar en otros navegadores.
function moveElement(id, x, y) { // mueve el elemento id a x,y // donde x,y son la posición horizontal // y vertical en píxeles var elm = null; if (document.getElementById) { // el navegador implementa parte de W3C DOM HTML // Gecko, Internet Explorer 5+, Opera 5+ elm = document.getElementById(id); } else if (document.all) { // Internet Explorer 4 u Opera con el agente de usuario IE elm = document.all[id]; } else if (document.layers) { // Navigator 4 elm = document.layers[id]; } if (!elm) { // navegador no admitido o elemento no encontrado } else if (elm.style) { // el navegador implementa parte de W3C DOM Style // Gecko, Internet Explorer 4+, Opera 5+ if (typeof(elm.style.left) == 'number') { // Opera 5/6 no implementa el estándar correctamente // y asume que elm.style.left y propiedades similares // son números. elm.style.left = x; elm.style.top = y; } else { // Gecko/Internet Explorer 4+ // W3C DOM Style establece que elm.style.left es una cadena // que contiene la longitud seguida de la unidad, p.e. 10px // Gecko le permitirá omitir la unidad sólo en el modo con // vericuetos (Quirks mode). // Gecko REQUIERE la unidad si opera en el modo de estándares. elm.style.left = x + 'px'; elm.style.top = y + 'px'; } } else if (typeof(elm.left) == 'number') { // Navigator 4 elm.left = x; elm.top = y; } }
Sólo con estándares
Considere lo sencilla que es esta función si la codifica de acuerdo a los estándares del W3C.
function moveElement(id, x, y) { // mueve el elemento id a x,y // donde x,y son la posición horizontal // y vertical en píxeles var elm = document.getElementById(id); if (elm) { elm.style.left = x + 'px'; elm.style.top = y + 'px'; } }
Pregúntese a sí mismo esto: "¿Dar cobertura a los navegadores no estándar compensa los costes de desarrollo y mantenimiento?"
Ejemplo 3 - Detectar ramas específicas de Gecko
// devuelve el valor rv de un agente de usuario Gecko // como un número de coma flotante. // devuelve -1 para navegadores no Gecko. // 0 para navegadores previos a Netscape 6.1/Gecko 0.9.1 // número > 0 donde cada porción del valor rv // delimitado por . se tratará como un valor // entre 0-99. // p.e. para rv: 3.12.42, // getGeckoRv() devuelve 3.1242 // function geckoGetRv() { if (navigator.product != 'Gecko') { return -1; } var rvValue = 0; var ua = navigator.userAgent.toLowerCase(); var rvStart = ua.indexOf('rv:'); var rvEnd = ua.indexOf(')', rvStart); var rv = ua.substring(rvStart+3, rvEnd); var rvParts = rv.split('.'); var exp = 1; for (var i = 0; i < rvParts.length; i++) { var val = parseInt(rvParts[i]); rvValue += val / exp; exp *= 100; } return rvValue; } // determina si el navegador es cualquier Gecko de la // rama >= 1.0.1 o Netscape 6.2.x/CompuServe 7 // compilado tras el 1 de agosto de 2002 var rv = geckoGetRv(); var found = false; if (rv >= 0) { // Navegador Gecko if (navigator.productSub > '20020801') { if (rv >= 1.0001) { found = true; } else if (rv >= 0.0904 && rv < 0.0905) { if (navigator.vendor == 'Netscape6' || navigator.vendor == 'CS 2000 7.0') { found = true; } } } }
Ejemplo 4 - The International Herald-Tribune
Este sitio ilustra muchas de las técnicas descritas en este artículo. Usan páginas básicas para los navegadores menos capaces combinadas con la detección de características basada en objetos para producir un sitio atractivo e interesante.
Ejemplos de DevEdge
* xbDOM * xbMarquee * xbPositionableElement * xbAnimatedElement
Conclusión
Como hemos visto en este artículo, la historia de detección de navegadores es aún bastante complicada debido a las diferencias entre los navegadores modernos tales como Gecko/Internet Explorer 6 y los navegadores más antiguos o no estándares tales como Netscape Navigator 4. Puede decirse a sí mismo "¡Si todos los navegadores fueran tan buenos como Gecko e Internet Explorer 6, entonces mi trabajo sería mucho más fácil!".
Me gustaría dejarle con esta idea. En el pasado, los usuarios no tenían la posibilidad de escoger un navegador que implementara los estándares; sin embargo hoy tienen esa elección. No hay razón convincente para que nadie en el mundo continúe usando un navegador que no implemente los estándares. Sin embargo, en la medida en que los desarrolladores web continúen codificando arreglos para estos navegadores antiguos, los usuarios no tendrán una motivación para actualizar. Al cesar de dar cobertura a los navegadores antiguos, puede proporcionar una razón a los usuarios para actualizar. Esto no sólo les beneficiará a ellos, sino también a usted. Tener en cuenta sólo a navegadores basados en estándares puede reducir los costes de desarrollo y mantenimiento así como incrementar el contenido dinámico y atractivo que atraerá visitantes e incrementará su beneficio. La elección es suya... ¡Decida apoyar a los estándares hoy!
Enlaces
- Manual de Compatibilidad de Gecko
- Cadenas de agente de usuario de Mozilla
- Referencia de interacción de modelo de objetos del documento - navegador
- Cadenas del User Agent de Gecko
- RFC 1945 - Hypertext Transfer Protocol -- HTTP 1.0
- RFC 2068 - Hypertext Transfer Protocol -- HTTP 1.1
- Mozilla's Quirks Mode
- CSS Enhancements in Internet Explorer 6
- W3C
Información del documento original
- Autor(s): Bob Clary
- Última actualización: 10 Feb 2003