Comment détecter des fonctionnalités au lieu des navigateurs

Mise à jour : décembre 2013

Traditionnellement, de nombreux développeurs sur Internet ont recours à la détection de navigateur en vue de fournir les mêmes modes de fonctionnement d’un navigateur à l’autre. Dans une implémentation standard, une opération de comparaison unique qui implique généralement la chaîne de l’agent utilisateur est effectuée, puis des hypothèses sont émises sur les fonctionnalités prises en charge par le navigateur en question. En pratique cependant, la détection de fonctionnalités s’avère être une technique plus efficace qui ne nécessite qu’une maintenance réduite. Cet article décrit comment utiliser la détection de fonctionnalités pour vérifier que les fonctionnalités normalisées sont bien prises en charge et illustre différentes méthodes permettant de détecter efficacement les fonctionnalités.

Les arguments contre la détection de navigateur

Dans une configuration standard, la détection de navigateur présente notamment les inconvénients suivants :

  • Lorsqu’un nouveau navigateur est commercialisé ou que la mise à jour d’un navigateur existant est publiée, vous devez ajouter le nouveau navigateur dans votre code de détection de navigateur. Les navigateurs mis à jour peuvent prendre en charge des normes et des fonctionnalités qui n’étaient pas prises en charge au moment où le code de détection de navigateur a été conçu.
  • Les conclusions relatives à la prise en charge des fonctionnalités risquent de ne pas être correctes ou appropriées.
  • De nombreux périphériques qui apparaissent sur le marché incluent de nouvelles versions des navigateurs ; par conséquent, le code de détection de navigateur doit être révisé et potentiellement modifié de façon à pouvoir prendre en charge ces nouveaux navigateurs. Dans certains cas, il devient plus compliqué de créer des implémentations personnalisées pour chaque navigateur.
  • Une technique de détection de navigateur peut ne pas identifier correctement un navigateur donné. Par exemple, de nombreux navigateurs sont capables de modifier la chaîne de l’agent utilisateur.

À titre d’exemple, prenez connaissance du code (incorrect) suivant, qui tente de manière inappropriée d’utiliser des techniques propres au navigateur pour affecter un gestionnaire d’événements.


function getInternetExplorerVersion()
// Returns the version of Internet Explorer or a -1
// (indicating the use of another browser).
{
  var rv = -1; // Default value assumes failure. 
  var ua = navigator.userAgent;

  // If user agent string contains "MSIE x.y", assume
  // Internet Explorer and use "x.y" to determine the
  // version.
 
  var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
  if (re.exec(ua) != null) 
    rv = parseFloat( RegExp.$1 );
  return rv;

}

function registerEvent( sTargetID, sEventName, fnHandler ) 
{
  var oTarget = document.getElementById( sTargetID );
  if ( oTarget != null ) { 

     // This is not an optimal example; it demonstrates 
     // techniques that you should not follow. 

     if ( getInternetExplorerVersion() > -1 ) { 
       oTarget.attachEvent( "on" + sEventName, fnHandler );
     } else {
       oTarget.addEventListener( sEventName, fnHandler ); 
     }
  }
}

Cet exemple illustre une tentative d’utilisation de la chaîne de l’agent utilisateur visant à déterminer si le navigateur est Windows Internet Explorer. Même si cet exemple fonctionne dans Internet Explorer et la plupart des navigateurs, il présente, entre autres, les inconvénients suivants :

  • Cet exemple de code se concentre sur le navigateur (Internet Explorer), non sur la fonctionnalité (inscription du gestionnaire d’événements DOM de niveau 3). Par conséquent, si Internet Explorer est utilisé pour consulter la page Web, l’exemple utilise attachEvent pour inscrire les gestionnaires d’événements même si la version d’Internet Explorer prend en charge la méthode addEventListener. En outre, cet exemple aurait besoin d’être testé avec toutes les nouvelles (hypothétiques) versions d’Internet Explorer.
  • Cet exemple suppose qu’Internet Explorer ne prend pas en charge la méthode addEventListener, ce qui est une hypothèse incorrecte en ce qui concerne Internet Explorer 9. Nombreuses sont les implémentations de détection de navigateur qui émettent des hypothèses de même type.
  • Alors que cet exemple particulier n’essaie pas de distinguer entre les versions d’Internet Explorer, des modifications ont été apportées à la manière dont Internet Explorer gère la chaîne de l’agent utilisateur. Les applications conçues sur la base du comportement des versions précédentes peuvent générer des résultats incorrects pour les pages Web affichées via l’affichage de compatibilité, proposé dans Internet Explorer 8. Pour plus d’informations, voir Présentation de la chaîne de l’agent utilisateur et Présentation de la liste d’affichage de compatibilité.

Cet exemple illustre les nombreuses faiblesses de la détection de navigateur en tant que technique d’identification des fonctionnalités prises en charge par un navigateur Web. Une approche plus efficace consiste à détecter directement la prise en charge de la fonctionnalité, comme indiqué dans l’exemple de code suivant.


function registerEvent( sTargetID, sEventName, fnHandler ) 
{
   var oTarget = document.getElementById( sTargetID );
   if ( oTarget != null ) 
   {
      if ( oTarget.addEventListener ) {   
         oTarget.addEventListener( sEventName, fnToBeRun, false );
      } else {
        var sOnEvent = "on" + sEventName; 
        if ( oTarget.attachEvent ) 
        {
           oTarget.attachEvent( sOnEvent, fnHandler );
        }
      }
   }
}

Cet exemple présente deux améliorations par rapport au scénario précédent :

  • Il est axé sur la fonctionnalité plutôt que sur le navigateur. Si l’utilisateur a recours à un navigateur qui prend en charge la méthode addEventListener (comme Internet Explorer 9 et de nombreux autres navigateurs), cette méthode permet de définir le gestionnaire d’événements.
  • Il privilégie les techniques normalisées par rapport aux techniques propriétaires. Dans ce cas, l’exemple vérifie si la technique privilégiée est prise en charge (la méthode addEventListener) avant de tenter d’utiliser l’autre technique.

Cet exemple est pertinent car il n’anticipe pas le comportement d’un navigateur donné. La technique n’a pas besoin d’être actualisée pour pouvoir prendre en charge de nouvelles (hypothétiques) versions d’Internet Explorer, ni d’être enrichie pour garantir la compatibilité avec de nouveaux navigateurs ou périphériques. L’exemple explique simplement comment s’assurer si une fonctionnalité est disponible ou pas. Il s’agit de la principale différence entre la détection de fonctionnalité et la détection de navigateur.

Dans un monde idéal, tous les navigateurs pourraient prendre en charge les mêmes normes et utiliseraient ces normes exactement de la même manière. En pratique cependant, il existe des différences entre les navigateurs et leur implémentation respective des diverses normes disponibles.

Pour les développeurs Web, la meilleure stratégie consiste à se fier aux fonctionnalités définies dans des normes largement prises en charge et stables, telles que HTML5, CCS3 (Cascading Style Sheets, Level 3), SVG (Scalable Vector Graphics), etc. La détection doit porter sur la prise en charge des fonctionnalités que vous souhaitez utiliser ; les approches alternatives ne doivent être fournies qu’en cas de nécessité.

Il existe un certain nombre de méthodes de détection des fonctionnalités, notamment les méthodes suivantes :

  • Recherche des objets ou propriétés DOM (Document Object Model) associés à la fonctionnalité.
  • Tentative de création d’un objet ou attribut lié à la fonctionnalité.
  • Utilisation de la méthode hasFeature pour déterminer si l’implémentation DOM prend en charge la fonctionnalité.

Pour plus d’informations, voir Comment créer des stratégies de secours efficaces.

Détection d’objets et de propriétés DOM

La méthode la plus courante pour détecter des fonctionnalités consiste à étudier les objets ou propriétés DOM associés à la fonctionnalité que vous souhaitez utiliser. Dans l’exemple suivant, le code indique comment savoir si le navigateur prend en charge la méthode addEventListener afin de définir un gestionnaire d’événements.


function registerEvent( sTargetID, sEventName, fnHandler ) 
{
   var oTarget = document.getElementById( sTargetID );
   if ( oTarget != null ) 
   {
      if ( oTarget.addEventListener ) {   
         oTarget.addEventListener( sEventName, fnToBeRun, false );
      } else {
        var sOnEvent = "on" + sEventName; 
        if ( oTarget.attachEvent ) 
        {
           oTarget.attachEvent( sOnEvent, fnHandler );
        }
      }
   }
}

Dans cet exemple, le code d’enregistrement d’événement vérifie que l’objet qui gère l’événement assure la prise en charge de la méthode addEventListener avant d’appeler la méthode pour enregistrer le gestionnaire d’événements. Ce scénario évite les erreurs de syntaxe d’exécution et fournit une approche alternative (également appelée stratégie de secours) si la technique privilégiée n’est pas prise en charge.

Pour déterminer si des objets, propriétés, attributs ou méthodes sont disponibles pour vous aider à détecter une fonctionnalité, reportez-vous à la spécification qui définit la fonctionnalité que vous souhaitez utiliser.

Par exemple, Internet Explorer 9 prend en charge l’objet performance de la spécification du chronométrage de la navigation. À ce jour, cette spécification définit l’attribut "window.performance". Par conséquent, vous pouvez utiliser la présence d’une propriété performance sur l’objet window pour déterminer si le navigateur Web actuel prend en charge la spécification du chronométrage de la navigation, comme indiqué dans l’exemple de code suivant.


if ( window.performance ) {
   showLoadTimes( window.performance );
}

Dans cet exemple, la fonction showLoadTimes() est appelée uniquement lorsque l’objet window prend en charge une propriété performance.

Création d’objets pour la prise en charge de fonctionnalités

Certaines fonctionnalités ne sont détectables dans le DOM que si le navigateur en effectue le rendu. Par exemple, Internet Explorer 9 prend en charge l’élément audio uniquement lorsqu’une page Web est affichée en mode Normes IE9. Si une page Web contenant un élément audio est affichée en mode IE5 (Quirks) (ou affichée par une version antérieure d’Internet Explorer), l’élément audio est rendu en tant qu’élément inconnu (générique).

Sur la base de la section précédente, l’exemple de code suivant peut sembler suffisant pour déterminer si un navigateur prend en charge l’élément audio.


<!doctype html>
<head>
<title>Simple Audio Support Test</title>

<script type="text/javascript">

   function supportsAudio() 
   {
     var d = document;
     var o = d.getElementById( "audio1" );
     return ( o != null ); 
   }

   function checkAudioSupport() 
   {
      var s = ( supportsAudio() == true ) ? 
              "supports " : "does not support ";
      var o = document.getElementById( "dOutput" );
      o.outerText = "Your browser " + s + "the audio element.";
   }

</script>

</head>
<body>
   <audio id="audio1" src="audiofile.mp3" />

    <button onclick="checkAudioSupport();">
        Click to test audio support.
    </button>
    <br />
    <div id="dOutput">Please click a button</div>

</body>
</html>

Cet exemple tente de créer un élément audio et base son évaluation de prise en charge de fonctionnalité en fonction du résultat (c’est-à-dire la création ou non de l’objet). Alors que cet exemple indiquerait correctement qu’Internet Explorer 9 prendrait en charge l’élément audio lorsque la page serait affichée en mode IE9, il prétendrait incorrectement la même chose lorsque la page Web serait affichée en mode IE5. La fonction supportsAudio() présume que la capacité à obtenir une référence à un objet créé par un élément audio est, en fait, un élément audio qui prend en charge la lecture de musique. Cela pose problème car les navigateurs Web sont supposés créer des références génériques aux éléments HTML qu’ils ne prennent pas en charge.


   function supportsAudio() 
   {
     var o = document.createElement( 'audio' );
     return ( o.canPlayType ); 
   }

En outre, cet exemple n’oblige pas la page Web à contenir un élément audio pour pouvoir déterminer la prise en charge de l’élément audio.

Dans les cas où le DOM ne contient pas d’objet ou de propriété DOM intégré(e) pour la fonctionnalité que vous souhaitez détecter, utilisez createElement ou une méthode équivalente pour créer un objet temporaire, puis vérifier que l’objet temporaire est le type d’objet qui vous intéresse.

Remarque  Pour obtenir les meilleurs résultats possibles, évitez d’émettre des hypothèses relatives aux navigateurs entre les appareils. Un navigateur de bureau peut prendre en charge des fonctionnalités différentes d’une version mobile du même navigateur qui peut lui-même différer du même navigateur sur un autre appareil. La détection de fonctionnalités vous permet de tester tous les navigateurs pour les fonctionnalités dont vous avez besoin.

Recherche des fonctionnalités DOM

La méthode hasFeature indique si les spécifications individuelles ou les ensembles de fonctionnalités définis par une spécification sont pris en charge. Par exemple, l’exemple de code suivant montre comment déterminer si un navigateur prend en charge SVG.


bResult = document.implementation.hasFeature("org.w3c.svg", "1.0")

Des chaînes de fonctions spécifiques sont définies par la spécification qui définit la fonctionnalité. Par exemple, la spécification DOM (Document Object Model) niveau 2 du W3C (World Wide Web Consortium) prend en charge une diversité de chaînes de fonctionnalité qui correspondent à des modules de la spécification globale.

Gardez à l’esprit que, même si la méthode hasFeature indique qu’un navigateur donné prend en charge une fonctionnalité spécifique, il est tout à fait possible que le navigateur ne supporte pas intégralement tous les aspects de la fonctionnalité en question. Si vous avez un doute, prenez le temps de rechercher des informations sur l’implémentation de la fonctionnalité dans les navigateurs les plus utilisés.

Pour plus d’informations sur le statut d’une spécification ou d’un ensemble de fonctionnalités donné(e), reportez-vous aux ressources fournies par l’organisme qui soutient la spécification. Par exemple, le site Web du W3C (World Wide Web Consortium) fournit une section Participation qui répertorie les ressources relatives au développement des normes W3C, notamment les thèmes de discussion publique, les mises à jour d’état et d’autres informations connexes.

Il existe de nombreux moyens permettant de détecter les fonctionnalités prises en charge par un navigateur Web. Veillez à recourir à des techniques de détection en rapport direct avec la fonctionnalité que vous souhaitez utiliser. Par exemple, il ne convient pas d’évaluer la couleur d’une zone de texte en vue d’identifier la police d’affichage de son contenu. En effet, des associations de ce type sont génératrices de problèmes.

 

 

Afficher:
© 2014 Microsoft