HTML : progress

Introduction à l'utilisation de l'élément progress, apparu dans les recommendations HTML 5.

Introduction

L'élément progress est un nouvel élément qui permet de créer un objet plutôt courant dans les librairies graphiques d'applications : représenter la progression d'un traitement, d'une tâche, d'une action. Il se traduit simplement par une barre verticale ou horizontale qui se « remplit » au cours du temps et dont l'apparence varit en fonction du navigateur web et du système d'exploitation.

<progress value="0.7">70%</progress>
Code HTML pour la création d'un élément progress.
70%
Rendu d'un élément progress par défaut, positionné à 70%.

Si vous affichez cette page avec Internet Explorer, Safari, Chrome < 6, Firefox < 6 ou Opera < 11, vous ne verrez que le texte contenu dans l'élément. Ces « anciens » navigateurs ne savent pas comment rendre un élément HTML portant le nom « progress ». Nous allons voir comment apporter un minimum de support avec un peu de CSS et du javascript.

Le principe est simple : la mise en forme de l'élément se fera à travers la classe « progress » ; celle-ci ne sera appliquée que si le navigateur ne gère pas nativement l'élément ; enfin, une fonction générique permettra de mettre à jour la valeur de progression. Par ailleurs :

  • Les fonctions seront volontairement simplifiées pour éviter de surcharger le code.
  • Toutes les caractéristiques de l'élément progress ne seront pas simulées (orientation, état indeterminé).

Il s'agit ici avant tout de comprendre et d'implémenter les bases du fonctionnement de l'élément.

Appliquer les traitements

La première étape consiste donc à déterminer si le navigateur gère nativement les éléments progress :

/**
 *  Le navigateur gère-t-il nativement progress ?
 *  @type Boolean
 */
var supportsProgress = ('value' in document.createElement('progress')) ? true : false;
Test de vérification du support natif de l'élément progress.

Si ce n'est pas le cas, nous allons chercher tous les éléments progress de la page pour les traiter convenablement avec une fonction dédiée, initProgress :

if (!supportsProgress) {
    var els = document.body.getElementsByTagName('progress'),
        i, n = els.length;
    for (i = 0; i < n; i++) {
        initProgress(els[i]);
    }
}
Lancement du traitement des éléments progress si nécessaire.

Initialiser les éléments

La fonction d'initialisation va effectuer plusieurs traitements :

  • Ajouter un élement enfant pour pouvoir simuler la progression.
  • Appliquer la classe progress qui permet la mise en forme.
  • Ajouter les propriétés value et max à l'élément.
  • Initialiser la valeur de progression.
/**
 *  Méthode d'initialisation des éléments progress
 *  @param {HTMLProgressElement} el Elément progress à initialiser
 */
var initProgress = function (el) {
    var
        // Element enfant à ajouter
        span = document.createElement('span');
        // contenu textuel de l'élément
        textNode = el.firstChild || document.createTextNode(' '),
        // Valeur de progression
        value = el.getAttribute('value') || 0,
        // valeur maximale
        maxi = el.getAttribute('max') || 1;
    // append markup
    span.appendChild(textNode);
    el.appendChild(span);                       
    // define className
    el.className = el.className + ' progress';
    // init values
    updateProgress(el, parseFloat(value, 10), parseFloat(maxi, 10));
};
Initialisation d'un élément progress.

Comme préciser plus haut, il s'agit ici d'une version simplifiée de ce qu'il faudrait faire. Nous devrions par exemple vérifier que l'élément ne contienne pas déjà un élément enfant, et utiliser celui-ci au lieu d'en créer un artificiellement.

Définir la valeur de progression

La modification de la valeur de progression est assurer par la fonction updateProgress, en faisant varier la taille de l'élément enfant que la fonction initProgress à préalablement inséré :

/**
 *  Mettre à jour la valeur d'un élément progress.
 *  @param {HTMLProgressElement} el Elément progress à initialiser.
 *  @param {Number} value Nouvelle valeur (doit être supréieure à -1).
 *  @param {Number} [maxi] Si la valeur maximale est aussi à modifier (doit être positive).
 */
var updateProgress = function (el, value, maxi) {
    if (maxi && maxi !== el.max) {
        el.max = maxi;
        el.setAttribute('max', maxi);
    }
    if (value < 0) {
        value = 0;
    } else if (value > el.max) {
        value = el.max;
    }
    if (value !== el.value) {
        el.value = value;
        if (!supportsProgress) {
            var w = (el.clientWidth * (el.value/el.max)) + 'px';
            if (value === null) {
                w = 0;
                el.removeAttribute('value');
            } else {
                el.setAttribute('value', value);
            }
            el.firstChild.style.width = w;
        }
    }
};
Mise à jour de la valeur de progression de l'élément.

Nous utilisons le test supportsProgress pour pouvoir utiliser la même fonction à la fois avec les navigateurs gérant nativement progress et ceux ne le gérant pas.

Là aussi, le traitement est simplifié : pour un élément progress vertical, les grandeurs à récupérer et à calculer ne seront pas les mêmes.

Mise en forme

Il ne nous reste plus qu'à définir les règles css pour assurer le rendu. Ce rendu variant grandement selon les navigateurs et le système d'exploitation, nous appliquerons un look dés plus simple.

.progress {
    /* flow content */
    display: inline-block;
    /* size */
    height: 1em;
    width: 10em;
    /* typo */
    font-size: 1em;
    line-height: 1;
    vertical-align: middle;
    /* box */
    padding: 0;
    margin: 0;
    /* borders */
    border-width: 1px;
    border-style: solid;
    -webkit-border-radius: 0.5em;
       -moz-border-radius: 0.5em;
            border-radius: 0.5em;
    /* colors */
    background: #E6E6E6;
    border-color: #666;
}
.progress > span {
    /* flow content */
    display: inline-block;
    /* size */
    height: 1em;
    /* borders */
    -webkit-border-radius: 0.5em;
       -moz-border-radius: 0.5em;
            border-radius: 0.5em;
    /* colors */
    background: #999;
    color: #999;
}
Règles CSS de base pour un élément progress.

Exemple d'utilisation

<p>
    <progress id="myProgress" value="0.2">20%</progress>
    <button id="update">Mise à jour</button>
</p>
Utilisation d'un élément progress avec un bouton de mise à jour.
// code javascript précédent

document.getElementById('update').addEventlistener('click', function (e) {
    var el = document.getElementById('myProgress');
    updateProgress(el, el.value + 0.2);
}, false);    
Ecoute du bouton pour mettre à jour la valeur de l'élément progress.

20%

Rendu de l'exemple.

Ressources et références

Titre
HTML 5
Auteurs
Ian HICKSON
Auteurs
Robin BERJON
Auteurs
Steve FAULKNER
Auteurs
Travis LEITHEAD
Auteurs
Erika DOYLE NAVARA
Auteurs
Edward O'CONNOR
Auteurs
Silvia PFEIFFER
Editeur
W3C
Date
Chapitre
4.10.14 The progress element
Titre
HTML 5
Auteurs
Ian HICKSON
Auteurs
Robin BERJON
Auteurs
Steve FAULKNER
Auteurs
Travis LEITHEAD
Auteurs
Erika DOYLE NAVARA
Auteurs
Edward O'CONNOR
Auteurs
Silvia PFEIFFER
Editeur
W3C
Date
Chapitre
10.5.12 The progress element
Titre
progress
Editeur
Mozilla Developer Network
Date