Skip navigation.

exploreopera

| Help

Sign up | Help

Guerra por los estándares

Estándares web, nueva guerra de los navegadores, tips de desarrollo web

Posts tagged with "navegadores"

Usando detección de capacidades en JavaScript

, , , ...

Hacia la detección de capacidades
El esnifeo de nombre del navegador y el utilizar scripts para deducir qué navegador se utiliza para proveerles diferentes contenidos es una práctica muy expandida con una larga historia. Desafortunadamente esos scripts son usualmente estáticos, mientras que los navegadores continúan evolucionando.

Esto hace que esos scripts sean extremadamente frágiles cada vez que aparece inesperadamente un nuevo navegador (o una nueva versión de algun navegador existente) que abra esa página. Poniéndolo simple: Esnifear nombres de navegador puede dañar seriamente la salud de tu script.

Entonces ¿por que esnifeamos?

Virtualmente todo script necesita saber algunas cosas acerca del navegador en el que corre. Hay 3 metas principales del esnifeo de nombre de navegador:
  • Detectar capacidades: soporte para cosas como DOM, ActiveX o Java, XMLHttpRequest
  • Detectar APIs: si un navegador ha nombrado a una característica de forma diferente, decir si debes usar event.target o event.srcElement
  • Solucionar bugs: Cuando un navegador simplemente no se comporta de manera correcta, y no puedes fingir que te olvidaste testear el sitio en ése navegador


Las mejores opciones

El objetivo es, después de todo, detectar las capacidades del navegador que muestra tu página. JavaScript tiene muchas características integradas que te dejan verificar cómo funcionan las cosas, sin ver los nombres de los navegadores para nada. Si pensamos en términos de detección de capacidades, resulta relativamente simple evitar el sniffing de navegador.

Para utilizar la detección de capacidad, comienza obteniendo una lista de las características requeridas por tu script. Entonces puedes utilizar la detección de objetos para ver si la característica existe. Recomiendo que también intentes llamar a algunas funciones seleccionadas para verificar tan en profundidad como sea posible que la característica realmente exista en el navegador visitante.
Detección apropiada de características
Como no hacerlo

No verifiques un objeto y asumas que otros estén disponibles. Por ejemplo, es común verificar por document.all y asumir que el visitante utiliza IE y que todas las funciones propietarias de IE pueden ser utilizadas
Cómo hacerlo
  1. Documenta lo que necesitas
  2. Verifica por funciones de la API seleccionadas de las características de las que tu script depende
  3. No tomes atajos
  4. Verifica si funcionan utilizándolas en un elemento/característica conocido

Ejemplo
Soporte de DOM

Un sitio importante utiliza la siguiente funcion para verificar si el navegador tiene soporte de DOM avanzado:
isDOM = false;
if (document.getElementById && 
   document.getElementById("assessDomNode")) {
   if (document.getElementById("assessDomNode").cloneNode &&
   document.getElementById("assessDomNode").cloneNode(true)) {
      isDOM = true;
   }
 }

Nota cómo ellos verifican si las funciones están disponibles con if(document.getElementById), y después proceden a llamar verdaderamente a la función y finalmente verifican si el navegador soporta el bastante avanzado método cloneNode compatible con DOM de W3C .

Algunas características no son tan directas de verificar, pero con algo de creatividad, muy pocas cosas son imposibles. Por ejemplo, si quieres verificar si el navegador soporta los bloques try ... catch, puedes incluír un archivo JavaScript separado o una etiqueta SCRIPT con el siguiente código:
 var trycatchsupported = false;
 eval(  'try{trycatchsupported = true;}catch(e){}'  ); 


Necesita estar en una etiqueta separada o al final de un script si quieres evitar que errores de sintaxis causados por el try ... catch detengan tu script principal.

hasFeature()

El estándar de DOM ha añadido un método para la detección de características, document.implementation.hasFeature(). Es llamado con un nombre de característica y un número de versión, por ejemplo document.implementation.hasFeature('HTML', '4.0'). Sin embargo, la característica de detección de objetos de Javascript te da información mucho más detallada, cross-navegador y confiable acerca de lo que está soportado.
Detección de la API apropiada

Manejar diferencias en la API es a menudo hecho escribiendo funciones de envoltura (wrapper functions) para las API que difieren. Un escenario muy común es obtener una referencia a un elemento específico en una página.
Cómo no hacerlo
  • Evita hacer asunciones todo lo que puedas acerca de qué partes de la API es soportada
  • Por ejemplo, no detectes HTMLElement y asume que __defineGetter__ está disponible para tu función de envoltura.
  • Evita establecer propiedades que puedan ser de sólo lectura en algunos navegadores. Por ejemplo, si manejas eventos de teclado e intentas establecer la propiedad event.which sin verificar que existe, los navegadores que sí soportan a event.which enviarán un error

Cómo hacerlo
Usa la detección de objetos para encontrar la API adecuada
Dentro de las funciones de envoltura, comienza con el método pas compatible a los estándares
Ejemplos

El ejemplo clásico es utilizar una función para obtener una referencia a un elemento en la página
function findElement(id){
   if(document.getElementById){ // primero el método estandarizado
      return document.getElementById(id);
   }else if(document.all){
      return document.all[id];
   }else if(document.layers){
      return document.layers[id];
   }else{
      return null;
   }
 }


Recuerda utilizarlo correctamente, verificando que de hecho retorne algo útil:
var elm=findElement('navigation');
if(elm){
   // haz lo que necesitas
}else{
   // Navegador muy viejo sin ningún soporte DOM. 
}

Manejo apropiado de bugs

La detección de navegadores basada en el nombre puede ser una parte del kit de herramientas para solucionar bugs en navegadores y versiones específicas, pero también deberías considerar si el script puede simplemente verificar si el bug existe.
Ejemplos

Aquí hay 2 ejemplos de cómo puedes verificar si existe alguna incompatibilidad, en vez de verificar por nombre y versión del navegador.
Incompatibilidad en la longitud de array

Una versión vieja de un script de menú DHTML muy popular contenía el siguiente código:
 if((navigator.userAgent.indexOf("Gecko")!=-1)){top_menu[top_menu.length] = null;}
 if((navigator.userAgent.indexOf("Konqueror")!=-1)){top_menu[top_menu.length] = null;}
 if(Nav4){top_menu[top_menu.length] = null;}



La razón para ese bloque de esnifeo es que crearon arrays que terminaron con una coma. De acuerdo a el estándar de ECMAScript, el array ['algo', ] tiene sólo un ítem en él, mientras que para IE tendrá dos. Para solucionar esta diferencia entre navegadores, el script agrega un elemento de array extra si detecta ciertos navegadores específicos.

Esto pudo haber sido hecho de manera mucho más simple verificando la longitud de un array literal para ver qué es lo que hace el navegador:

 if( ['',].length == 1 ){top_menu[top_menu.length] = null;}

cloneNode() y datos de usuario

Un sitio de blog muy popular contiene el siguiente código:
if (Detect.SAFARI() || Detect.OPERA()) {
   // cloneNode no está capturando atributos de nodo o valores para algunos navegadores
   this.textarea.value = this.textarea_orig.value;
   this.textarea.name = this.textarea_orig.name;
   this.textarea.id = this.textarea_orig.id;


El problema es que utilizando cloneNode en un elemento form no clona ningun cambio que el usuario haya hecho en el elemento. El siguiente reemplazo busca el bug en vez de el navegador:
  if ( this.textarea.value != this.textarea_orig.value ) {
   // cloneNode no está capturando atributos de nodo o valores para algunos navegadores
   this.textarea.value = this.textarea_orig.value;
   this.textarea.name = this.textarea_orig.name;
   this.textarea.id = this.textarea_orig.id;


Hacia la detección de capacidades - un script para comenzar

Para escribir scripts que manejarán navegadores futuros y nuevas versiones correctamente, debes dejar atrás el modo de pensar de detección de navegadores cuando sea posible. Las buenas noticias son que esnifear el nombre del navegador es raramente necesario. La mayor parte del tiempo, es mucho más fácil detectar si las funciones y características que necesitamos son soportadas.

Para que comiences, un script de demostración de detección de capacidades. Algunas características:
  • Detecta varios niveles de soporte de DOM
  • Detecta soporte de VBScript
  • Detecta selección de texto / capacidades de editado WYSIWYG
  • Agrega atributos personalizados al objeto navigator en vez de crear variables globales o un objeto de esnifeo específico. El objeto navigator es creado para proveer información acerca del ambiente del script, así que hagamos un buen uso de él.


Te alentamos a que utilices y modifiques el script. Considera las características que tu aplicación de JavaScript necesita y quita las partes que no utilizas.
Otras Fuentes:


Traducido por: Guillermo Nuñez
Autor Original: Hallvord R. M. Steen
Fuente: Dev.Opera